内部类

发布时间 2023-10-18 22:46:06作者: Ohana+

内部类

前言

内部类是定义在另一个类中的类:

  • 内部类可以对同一个包中的其他类隐藏;
  • 内部类方法可以访问定义这个类的作用域中的数据,包括原本私有的数据;

使用内部类访问对象状态

内部类的对象有一个「隐式引用」,指向实例化这个对象的外部类对象。通过这个指针,可以访问外部对象的全部状态。

注:静态内部类没有这个指针。

内部类方法不仅可以访问自身的数据字段,还可以通过「隐式引用」访问创建它的外部类对象的数据字段。

// Outer类中存在一个beef数据字段,Inner类是Outer类的内部类
public class Outer {
  
  private int beef;
  
  public class Inner {
    public void doPrint() {
      System.out.println(beef);
    }
  }
}

编译器会修改所有的内部类构造器,添加一个外部类引用的参数。

注:内部类可以是私有的。

内部类的特殊语法规则

表示外部类引用的语法:OuterClass.this

// Outer类中存在一个beef数据字段,Inner类是Outer类的内部类
int innerBeef = Outer.this.beef;

使用明确的内部类对象的构造器构建内部类对象:

outerObject.new InnerClass(construction parameters)

Inner inner = outerObject.new Inner();

在外部类的作用域之外,可以这样引用内部类:OuterClass.InnerClass

注1:内部类中声明的所有静态字段都必须是final,并初始化为一个编译时常量。

注2:内部类中不能有statis方法。

内部类是否有用、必要和安全

内部类可以访问外部类的私有数据,但是外部类不可以访问内部类的数据。

局部内部类

可以在一个方法中局部地定义一个内部类,这个类称为局部内部类。

public void outerFunction() {
  // 在一个方法中定义一个局部内部类
  class InnerClass {
    public void innerFunction() {
      System.out.println("test");
    }
  }
}

局部内部类对外部世界完全隐藏,除了所在的方法,没有其他任何方法知道其存在。

注1:声明局部内部类时不能有访问说明符(即publicprivate)。

注2:局部内部类的作用域被限定在声明这个局部类的代码块中。

由外部方法访问变量

与常规内部类相比较,局部内部类不仅可以访问外部类的字段,还可以访问方法内的局部变量。

注:这些局部变量必须是事实最终变量(即final修饰的变量)。

匿名内部类

使用局部内部类时,可以只创建这个类的对象,而不需要为这个类指定名字,这个类被称为「匿名内部类」。

// 在一个方法中定义一个局部内部类
new SupperType(construction parameters) {
  public void innerFunction() {
    System.out.println("test");
  }
}
// 在一个方法中定义一个局部内部类
new InterfaceType() {
  public void innerFunction() {
    System.out.println("test");
  }
}

注1:SupperType是类,InterfaceType是接口,匿名内部类是对类或接口的拓展。

注2:由于构造器的名字必须与类名相同,而匿名内部类没有类名,所以,匿名内部类不能有构造器。

实现SupperType的匿名内部类可以存在构造参数,实际上,这些构造参数是传递给超类构造器的。

SupperType object = new SupperType("value1","value2") {
  // method and data
}

实现InterfaceType的匿名内部类不可以存在任何构造参数,可以提供一个对象初始化块,初始化参数。

InterfaceType object = new InterfaceType() {
  {
    // initialization
  }
}

静态内部类

使用内部类有可能只是为了把一个类隐藏在另外一个类的内部,并不需要内部类有外围类对象的引用。

可以将这个内部类声明为static(即静态内部类),这样就不会生成外围类对象的引用了。

注1:静态内部类可以有静态字段和静态方法。

注2:在接口中声明的内部类自动是staticpublic