内部类
内部类是定义在类中的类,其主要优点如下:
- 内部类方法可以访问定义所在类中的数据。
- 内部类可以对同一个包中其他类隐藏。
- 可以快捷地定义回调函数。
特殊语法
外围类引用OuterClass.this
表示内部类对外围类的引用。
相反地,outerObject.new InnerClass(construction parameters)
用于编写内部类的构造器。
在外围类的作用域之外,通过OuterClass.InnerClass
引用内部类。
内部类中声明的所有静态域都必须是final
。
内部类不应有静态方法。
内部类机制
在编译时,编译器将内部类翻译为用$分隔外部类名与内部类名的常规类文件,这导致虚拟机无法辨别。
但实际上,内部类又比常规类有更大的访问权限。这是因为编译器在外围类添加静态方法,将返回作为参数传递给它的对象域。内部类将调用这些静态方法,以获取外围类的变量的值。
这种机制实际上存在一定的安全隐患,可以在外围类的包中创建一个用虚拟机指令调用编译器添加的静态方法的类文件,以此来读取外围类的私有变量。当然,这种攻击方式十分困难。
局部内部类
与成员内部类不同,局部内部类定义在方法之中,不能使用public
或private
声明,其作用域被限定在声明该局部类的块中。这样的声明可以将局部内部类隐藏,使得仅在这个块中可以访问它。
局部内部类还可以访问声明为final
的局部变量,这个特点和lambda表达式的最终变量是类似的。
注意:若要让局部内部类访问局部变量,编译器会为其构造器添加局部变量的类型作为参数,同时在局部内部类中添加局部变量的final
类型副本(这是一个新的变量)。
匿名内部类
若一个内部类只创建一个对象,则不需要为其命名,称其为匿名内部类。
匿名内部类的语法格式通常如下:
new SuperType(construction parameters) {
inner class methods and data
}
匿名内部类可以用于实现事件监听器和其他回调,但更应使用lambda表达式作为代替,可读性和简洁性更强。
注:在静态方法中直接调用getClass
方法是不奏效的。因为调用getClass
实际是调用this.getClass
,但静态方法没有this
参数。因此可以建立Object
的匿名子类的匿名对象,通过getEnclosingClass
来获取外围类。
// 该表达式可以获取包含静态方法的类
new Object(){}.getClass().getEnclosingClass()
静态内部类
当隐藏的内部类不需要引用外围类对象时,可以将其声明为static
,称其为静态内部类。
由于静态内部类不引用其他对象,静态内部类没有对生成它的外围类对象的引用特权,其余和其他内部类一样。