内部类
前言
内部类是定义在另一个类中的类:
- 内部类可以对同一个包中的其他类隐藏;
- 内部类方法可以访问定义这个类的作用域中的数据,包括原本私有的数据;
使用内部类访问对象状态
内部类的对象有一个「隐式引用」,指向实例化这个对象的外部类对象。通过这个指针,可以访问外部对象的全部状态。
注:静态内部类没有这个指针。
内部类方法不仅可以访问自身的数据字段,还可以通过「隐式引用」访问创建它的外部类对象的数据字段。
// 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:声明局部内部类时不能有访问说明符(即public或private)。
注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:在接口中声明的内部类自动是static和public。