Java - 29 内部类

Java - 内部类

一个类的内部 又完整地嵌套了另一个类结构,被嵌套的内为 内部类

内部类 - 外部类 - 外部其他类

类的五大成员:属性;方法;构造器;代码块;内部类

class Outer{
  class Inner{
    
  }
}

定义在外部类 局部位置 上(通常在 方法 /代码块 中)

局部内部类(有类名)

  • 本质还是一个类,作用域在 定义它的方法或代码块中
  • 可以直接访问外部类的所有成员,包括私有的
  • 不能添加访问修饰符,可以使用 final 修饰
class Outer{
  private int n = 1;
  private void m2(){}
  public void m1(){
    // 不能添加访问修饰符,可以使用 final 修饰
    class Inner01{ // 本质还是一个类,作用域在 定义它的方法或代码块中
      // 可以直接访问外部类的所有成员,包括私有的
      public void f1(){
        System.out.println("n1="+n1);
        m2();
      }
    }
    class Inner02 extends Inner01{}
    
    // 外部类在方法中可以创建Inner对象,然后调用方法即可
    Inner01 in = new Inner01();
    in.f1();
  }
}

匿名内部类(没有类名)

new 类或接口(参数列表){
  
}
  • 本质是类,作用域在 定义它的方法或代码块中
  • 该类没有名字(但系统会分配一个我们看不到的名字)
  • 匿名内部类 使用一次就不能再使用了
  • 可以直接访问外部类的所有成员,包括私有的
  • 同时 还是一个对象
  • 局部变量不能使用访问修饰符
  • 外部类与匿名内部类的成员重名时,匿名内部类的访问遵循就近原则,使用外部类.this.成员 访问外部成员
class A{
  private n1 = 1;
  public A(){}
  
  public void me(){
    // ia编译类型:IA,运行类型:匿名内部类
    // jdk底层创建匿名内部类后立马创建了对象
    IA ia = new IA(){
      @override
      public void cry(){
        System.out.println("...");
      }
    };
    ia.cry();
    ia.getClass(); // A$1
    
    // 参数列表会传给 Father 的构造器
    Father f = new Father("Hu"){
      private n1 = 88;
      @override
      public void test(){
        System.out.println("匿名内部类重写了test()");
        // 访问外部 n1
        System.out.println(A.this.n1); // 1
      }      
    };
    f.getClass(); // A$2
  }
}

interface IA{
  void cry();
}
class Father{
  public Father(String name){}
  public void test(){}
}

最佳实践

当作实参直接传递

class Main{
  public static void main(String[] args){
    f1(new IL(){
      @Override
      public void show(){
        System.out.println("show");
      }
    });
  }
  public static f1(IL il){
    il.show();
  }
}

interface IL{
  void show();
}

定义在外部类 成员位置 上

成员内部类(没用static修饰)

class Main{
  public static void main(String[] args){
    // 外部其它类访问成员内部类1
    Outer ot = new Outer();
    Outer.Inner inner1 = ot.new Inner();
    // 外部其它类访问成员内部类2
    Outer.Inner inner2 = ot.getInnerInstance();
  }
}

class Outer{
  private int n1 = 1;
  
  public class Inner{
    private double sal = 99.8;
    public void say(){
      System.out.println(n1); // 直接访问外部类成员
    }
  }
  
  public void t1(){
    // 创建对象再访问
    Inner inner = new Inner();
    inner.say();
    System.out.println(sal); // 99.8
  }
  
  // 返回成员内部类对象的方法
  public Inner getInnerInstance(){
    return new Inner();
  }
}
  • 作用域为整个类

  • 成员内部类 可以直接访问外部类的所有成员,包括私有的

  • 外部类 访问 成员内部类 需要创建对象再访问

  • 外部其它类访问成员内部类 有两种方法

  • 可以添加任意访问修饰符,因为 它的地位是成员

    • 成员内部类是外部类的一部分,这种嵌套关系使得外部类能够访问内部类的所有成员,包括私有成员
  • 外部类与成员内部类的成员重名时,匿名内部类的访问遵循就近原则,使用外部类.this.成员 访问外部成员

静态内部类(使用static修饰)

class Main{
  public static void main(String[] args){
    // 外部其它类访问静态内部类1
    Outer.Inner inner1 = new Outer.Inner();
    // 外部其它类访问静态内部类2
    Outer.Inner inner2 = new Outer.getInner();
    Outer.Inner inner3 = Outer.get_Inner();
  }
}

class Outer{
  private int n = 10;
  private static String name = "hello";
  
  static class Inner{
    public void say(){
      System.out.println(name);
    }
    public Inner getInner(){
      return new Inner();
    }
    public static Inner get_Inner(){
      return new Inner();
    }
  }
}
  • 作用域为整个类
  • 静态内部类 可以直接访问外部类的所有静态成员,包括私有的,但不能访问非静态成员
  • 外部类 访问 静态内部类 需要创建对象再访问
  • 外部其它类访问静态内部类 有两种方法
  • 可以添加任意访问修饰符,因为 它的地位是成员
  • 外部类与静态内部类的成员重名时,静态内部类的访问遵循就近原则,使用外部类.成员 访问外部静态成员
posted @ 2024-11-07 19:39  wajiez  阅读(18)  评论(0)    收藏  举报