美文网首页
Java 内部类

Java 内部类

作者: Tinyspot | 来源:发表于2022-07-25 14:08 被阅读0次

    1. 内部类

    概念:在一个类的内部再定义一个完整的类
    内部类分为 4 类:成员内部类、静态内部类、局部内部类、匿名内部类

    1.1 特点

    1. 编译之后可生成独立的字节码文件
    2. 内部类可直接访问外部类的私有成员,而不破坏封装
    3. 可为外部类提供必要的内部功能组件

    内部类的作用:
    1.可以无条件地访问外部类的所有元素
    2.实现隐藏:外部类即普通的类不能使用 private, protected 访问权限符来修饰的,而内部类则可以使用 private 和 protected 来修饰
    3.可以实现多重继承(多个内部类分别继承别的类)
    4.通过匿名内部类来优化简单的接口实现

    1.2 补充

    • 编译后,生成各自的class文件,内部类通过 this 访问外部类的成员
    • 外部类与内部类之间使用 $ 符号分隔,示例 Outer.class, Outer$Inner.class
    • 匿名内部类使用数字进行编号,示例 Outer.class, Outer$1.class
    • 成员内部类是依附外部类而存在的,静态内部类不依附外部类

    2. 成员内部类

    1. 成员内部类与实例变量、实例方法同级别
    2. 成员内部类是依附外部类而存在的,创建成员内部类对象时,必须依赖外部类对象
    3. 当外部类与内部类的属性重名时,优先访问内部类属性
    4. 成员内部类不能定义静态成员,但可以包含静态常量 final
    public class Outer {
        private String name = "Bob";
    
        // 默认作用域:包内可见
        public class Inner {
            private String name = "Alice";
            // 4. 静态常量 final
            private static final String address = "...";
            
            public void show() {
                System.out.println(name); // 等价 this.name
                // 3. 属性相同时,外部类使用 Outer.this
                System.out.println(Outer.this.name);
            }
        }
    }
    
    // 2. 实例化成员内部类
    Outer outer = new Outer();
    Outer.Inner inner = outer.new Inner();
    // or
    Outer.Inner inner = new Outer().new Inner();
    

    2.1 接口中的成员内部类

    可以有静态属性

    public interface OuterInterface {
        class Inner {
            private static String address = "";
            public void show() {
                
            }
        }
    }
    // demo
    OuterInterface.Inner inner = new OuterInterface.Inner();
    inner.show();
    

    3. 静态内部类

    1. 不依赖外部类对象,可通过类名访问
    public class Outer {
        private String name = "Bob";
    
        public static class Inner {
            private String name = "Alice";
            // 静态成员
            private static String address = "...";
    
            public void show() {
                // 调用外部类的属性,先创建外部类对象
                Outer outer = new Outer();
                System.out.println(outer.name);
                // 调用静态内部类的属性
                System.out.println(name);
                // 调用静态内部类的静态属性
                System.out.println(Inner.address);
            }
        }
    }
    // demo
    Outer.Inner inner = new Outer.Inner();
    inner.show();
    

    4. 局部内部类

    1. 定义在外部类方法中,作用范围和创建对象的范围仅限于当前方法
    2. 局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,所以该局部变量必须修饰为 final
    3. 局部内部类也不能定义静态成员,但可以包含静态常量 final
    public class Outer {
        private String name = "Bob";
    
        public void show() {
            String address = "...";
    
             // 局部内部类在 方法 里声明
            class Inner {
                private Integer age;
                public void innerShow() {
                    System.out.println(Outer.this.name);
                    // 局部内部类里访问局部变量,JDK1.7 要求变量必须是常量final,JDK1.8 自动添加final
                    System.out.println(address);
                    // Variable 'address' is accessed from within inner class, needs to be final or effectively final
                    // address = "111";
                }
            }
            Inner inner = new Inner();
            inner.innerShow();
        }
    }
    
    // demo
    Outer outer = new Outer();
    outer.show();
    

    address 为什么是 final
    address 若是一个普通属性,当 show() 方法执行完之后,局部变量 address 就会消失
    show() 里面的 Inner inner = new Inner(); new Inner() 在堆里,不会立即消失,innerShow() 属于类 Inner 也不会立即消失
    变量 address 没有了,但类还在,不合理,所以是 final 类型

    5. 匿名内部类(Anonymous Classes)

    • 没有类名的局部内部类(一切特征都与局部内部类相同)
    • 必须继承一个父类或者实现一个接口(用来创建接口或抽象类的实例)
    • 匿名内部类是唯一一种没有构造器的类,大部分匿名内部类用于接口回调

    语法 new 父类() { 子类内容 };
    匿名类是一个表达式,因此在定义的最后用分号;结束

    5.1 示例

      // 继承类
      Thread thread = new Thread() {
          @Override
          public void run() { // ... }
      };
      thread.start();
    
      // 实现接口
      Runnable runnable = new Runnable() {
          @Override
          public void run() { // ... }
      };
    

    5.2 局部内部类改为匿名内部类

    public static void main(String[] args) {
        // 局部内部类(定义在方法中的类)
        class Mouse implements Usb {
            @Override
            public void service() {
                System.out.println("Mouse run....");
            }
        }
        Usb usb = new Mouse();
        usb.service();
    }
    

    局部内部类使用一次后就不再使用,优化方式:改为匿名内部类

    public static void main(String[] args) {
        // 相当于创建了一个局部内部类
        Usb usb = new Usb() {
            @Override
            public void service() {
                System.out.println("run...");
            }
        };
        usb.service();
    }
    

    5.3 为什么局部变量需要 final修饰

    public static void main(String[] args) {
        int num = 0; // JDK1.7前,必须加上 final
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(num++); // 报错,num 不能操作
            }
        };
    }
    

    因为局部变量和匿名内部类的生命周期不同
    匿名内部类是创建后是存储在堆中的,而方法中的局部变量是存储在Java栈中,当方法执行完毕后,就进行退栈,同时局部变量也会消失

    5.4 其他示例

    public class Demo {
        public static void main(String[] args) {
            // 匿名内部类  Demo$1
            List<String> list = new ArrayList<String>() {{
                    add("111");
                    add("222");
            }};
        }
    }
    
    public void test() {
        // 创建接口实例
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
        // 匿名类的实例作为参数传递  TreeSet(Comparator<? super E> comparator) {}
        TreeSet<Integer> ts = new TreeSet<>(comparator);
    
      // 或者
      TreeSet<Integer> ts = new TreeSet<>(new Comparator<Integer>() {
          @Override
          public int compare(Integer o1, Integer o2) {
              return Integer.compare(o1, o2);
          }
      });
    }
    

    6. 非公有类

    • 非公有类不能使用public关键字
    • 内部类和非共有类,可以与其他类共用一个文件
    • 一个源文件中可以包含多个非公有类或者内部类;

    7. 内部类实现接口

    相关文章

      网友评论

          本文标题:Java 内部类

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