OnJava8笔记5 -- 内部类

内部类

一个定义在另一个类中的类,叫作内部类。

创建内部类

public class Parcel {
    class Contents {
        private int i = 11;

        public int value() { return i; }
    }
}
  • 在Parcel之外的类中想要创建Contents对象,需要 Parcel.Contents ( OuterClassName.InnerClassName )

  • 内部类自动拥有对其外围类所有成员和方法的访问权,即使是 private 的也可以。这是因为当内部类对象被创建时,一个外部类对象的引用被传递给这个内部类对象了。

  • 普通内部类不能有 static 字段和方法

内部类中的 .this 和 .new

.this

  • 在内部类中, *OuterClassName.this *(DotThis.this) 代表的是外部类对象的引用,单纯的 this 就是内部类对象的引用

.new

  • 外部类对象.new 用于创建内部类对象

    public class DotNew {
        public class Inner {}
        public static void main(String[] args) {
            DotNew dn = new DotNew();
            DotNew.Inner dni = dn.new Inner();
        }
    }
    

方法和作用域中的内部类

public class Parcel6 {
    private void internalTracking(boolean b) {
        if(b) {
            class TrackingSlip {
                private String id;
                TrackingSlip(String s) {
                    id = s;
                }
                String getSlip() { return id; }
            }
            TrackingSlip ts = new TrackingSlip("slip");
            String s = ts.getSlip();
        }
        // Can't use it here! Out of scope:
        //- TrackingSlip ts = new TrackingSlip("x");
    }
}

内部类只能在自己的作用域中能被使用

  • 方法和作用域中的内部类使用的外部变量必须是final的

匿名内部类

public interface Contents {
    int value();
}
public class Parcel7 {
    public Contents contents() {
        return new Contents() { // Insert class definition
            private int i = 11;

            @Override
            public int value() { return i; }
        }; // Semicolon required
    }

    public static void main(String[] args) {
        Parcel7 p = new Parcel7();
        Contents c = p.contents();
    }
}

在创建 Contents 对象代码之后插入一个类的声明,这个插入的类就是匿名类(没有具体名字)

  • 这里可以看成创建了一个继承自 Contents 的匿名类对象,然后通过前面的 new 表达式将匿名类对象向上转型成 Contents 对象
  • 匿名内部类中使用的外部变量必须是final 的
  • 匿名内部类,因为是匿名的,不能显式声明构造函数

匿名内部类中的参数初始化

public class Parcel9 {
    // Argument must be final or "effectively final"
    // to use within the anonymous inner class:
    public Destination destination(final String dest) {
        return new Destination() {
            private String label = dest;
            @Override
            public String readLabel() { return label; }
        };
    }
    public static void main(String[] args) {
        Parcel9 p = new Parcel9();
        Destination d = p.destination("Tasmania");
    }
}

可以看到第6行用到的外部变量是final的(jdk8之后不用明确写final了,但还是不能被改变)
为什么必须是final的? 参考知乎 胖君 的回答:https://www.zhihu.com/question/21395848

嵌套类

static类型的内部类叫做嵌套类。嵌套类对象没有指向外部创建他的类的对象引用

  • 要创建嵌套类对象,不需要外部类对象
  • 不能从嵌套类的对象中访问非静态外部类的对象
  • 嵌套类可以包含 static 字段和方法
  • 接口中的内部类自动是 public 和 static 的

为什么要使用内部类

  • 最重要的原因是可以间接实现类的多继承

    我们知道java中的类只能单继承,内部类可以间接实现多继承:

    public class Demo1 {
          public String name() {
              return "BWH_Steven";
          }
      }
      
      public class Demo2 {
          public String email() {
              return "xxx.@163.com";
          }
      }
      
      public class MyDemo {
      
          private class test1 extends Demo1 {
              public String name() {
                  return super.name();
              }
          }
      
          private class test2 extends Demo2  {
              public String email() {
                  return super.email();
              }
          }
      
          public String name() {
              return new test1().name();
          }
      
          public String email() {
              return new test2().email();
          }
      
          public static void main(String args[]) {
              MyDemo md = new MyDemo();
              System.out.println("我的姓名:" + md.name());
              System.out.println("我的邮箱:" + md.email());
          }
    }
    

    在MyDemo类中书写了两个内部类,test1和test2 两者分别继承了Demo1和Demo2类,这样MyDemo中就间接的实现了多继承

  • 使用匿名内部类实现回调功能(jdk8之后可以使用lambda表达式)
    当有这么个需求,一个方法的参数是接口对象,因为接口不能生成对象,而单独写一个类来实现接口又太浪费(因为这个方法可能只会被使用一次),这时匿名内部类很容易实现这一需求

    interface Demo {
        void interfaceMethod();
    }
    
    public class NiMingInnerClass {
    
        public void test(Demo demo) {
            demo.interfaceMethod();
        }
    
        public static void main(String[] args) {
            NiMingInnerClass innerClass = new NiMingInnerClass();
            innerClass.test(new Demo() {
                @Override
                public void interfaceMethod() {
                    System.out.println("接口方法被调用了");
                }
            });
        }
    }
    
  • 父类和接口中存在同名方法,而直接Override这个方法会导致只能保留一个方法,想要既保留继承自父类的实现,又保留接口中的方法,这时选择内部类很容易达到需求

    interface Demo2 {
        void test();
    }
    abstract class  SupClass {
        public void test() {
            System.out.println("SupClass test()");
        }
    
    }
    
    public class SameNameMethod extends SupClass {
        @Override
        public void test() {
            super.test();
            System.out.println("SameNameMethod test()");
        }
    
        private class InnerClass implements Demo2{
            @Override
            public void test() {
                System.out.println("Demo2 test()");
            }
    
    
        }
    
        public InnerClass getInner() {
            return new InnerClass();
        }
        public static void main(String[] args) {
            SameNameMethod test = new SameNameMethod();
            test.test();
            test.getInner().test();
        }
    }
    
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容