美文网首页
OnJava8笔记5 -- 内部类

OnJava8笔记5 -- 内部类

作者: 给点阳光我就灿烂_ab56 | 来源:发表于2020-04-19 19:56 被阅读0次

    内部类

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

    创建内部类

    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();
          }
      }
      

    相关文章

      网友评论

          本文标题:OnJava8笔记5 -- 内部类

          本文链接:https://www.haomeiwen.com/subject/spnbbhtx.html