类的成员之内部类
类的成员包括5个:属性、方法、构造器、代码块和内部类。
1 什么是内部类
定义在类中的类,称为内部类,相应地,内部类所在的类称为外部类。
内部类本质上仍是类。
类中的变量、代码块和内部类可以定义在类的其他成员中,称为局部结构。
内部类根据是否定义在类的其他成员中(指构造器、方法和代码块),可以分为:成员内部类和局部内部类。
2 成员内部类
成员内部类是指定义在类中而非类中的成员中,作为类的成员的类。
成员内部类既作为类,也作为类的成员,因此具备这2方面的特性:
1) 作为类的成员:
- 可以被4种权限修饰符修饰,而外部类只能被
public
和默认修饰符修饰; - 可以被
static
关键字修饰,而外部类不能用static
关键字修饰; - 内部类和外部类都可以被类的其他成员使用,区别在于外部类可以被其他类使用,而内部类只能用于其外部类。
2) 作为类:
- 可以继承其他类,也可以作为接口的实现类;
- 可以用
abstract
和final
关键字修饰。
简单地说,内部类仍是类,具备类的所有特性。
3 局部内部类
局部内部类是定义在类的成员中的类,不属于类的成员。
与成员内部类的区别在于,其作用范围局限于其所在结构,可以理解为非类的成员,而是某结构的成员,因此局部内部类并没有成员内部类作为类的成员的特性。
局部内部类只能作用于其所在结构,但能使用其结构所在的类中的成员或其他其能使用的结构。
可以将局部内部类看作一种特殊的“局部变量”。
4 内部类的实例化
根据内部类是否随其外部类加载而加载,即是否被static
修饰,其实例化方式不同:
1) static内部类
的实例化:new 外部类.内部类构造器
;
2) 非static内部类
的实例化:外部类对象.new 内部类构造器
.
不论是static
还是非static
内部类,内部类在外部类外的类型为:外部类.内部类
。
由于局部内部类只作用于其所在结构,不存在在外部类外使用,因此这里讨论的内部类的实例化是指成员内部类的实例化。
5 内部类成员与外部类成员的使用区别
- 在内部类中,使用自己有的成员,可直接使用,或通过
this.
的方式; - 在内部类中,使用外部类中的能用的成员(static结构无法使用非static结构),如果自己没有,可直接使用,如果自己有,要区分开来,通过
外部类.this.
的方式使用外部类成员。 - 在外部类中,使用内部类的
非static
成员,通过对应对象来使用,对于static
成员(此时内部类也为static的),直接通过内部类.
的方式使用。
注意,只有static
内部类才能定义自己的static
成员。
可以这样理解:static
代表仅一份,如果非static
内部类可以定义自己的static
成员,那么由于每个外部类对象都会有一个对应的非static
内部类结构,也就都会有一份该内部类的static
成员,矛盾。
6 局部内部类的使用场景
一个典型的局部内部类的使用场景是:
一个方法,其返回值类型为某接口,代表该方法的功能为返回对应接口对应的类对应的对象,此时需要通过实例化该接口的实现类来实现。
这种场景下,可以在方法体内定义局部内部类作为该接口的实现类,进而得到对应实例化对象,以实现功能。
7 其他关于内部类的注意点
1) 不论是成员内部类还是局部内部类,在编译时都会生成对应的字节码文件。不同内部类的字节码文件命名格式不同:
- 普通类: 类名.class
- 成员内部类:外部类名$成员内部类名.class
- 局部内部类:外部类名$数字 内部类名.class(由于局部内部类属于局部结构,不同结构的局部结构可以重名,因此用数字给每个局部内部类标识)
2) 局部内部类使用注意点
如果局部内部类使用了其所在结构中的局部变量,那么该局部变量在被局部内部类使用之前值要确定,且一旦值确定就不可变,相当于final局部变量
。
换句话说,使用在局部内部类中的局部变量,不论该局部变量在定义时是否声明为final
,该局部变量在被局部内部类使用之前要确定值,且值一点确定就不可变。
理解:由于内部类在编译时也会生成对应的类的字节码文件,因此不论是局部内部类还是成员内部类编译时是与其外部类分开的单独的文件。
由于局部内部类所在结构属于其外部类的成员,因此编译时处于外部类的文件中,即局部内部类除了其本身类的结构外,其他所有相关联的结构都在另一个其外部类对应的文件中。
因此,如果局部内部类使用其所在结构的局部变量时,若对其进行修改,也只能对自己所在文件进行修改操作,这种修改操作无法传到另一个文件,同理,若其所在结构对该局部变量修改,该操作也只能对其所在的外部类对应的文件进行操作,也无法传到其局部内部类所在的文件。
因此,局部内部类所在结构中,只有值确定且不可变的局部变量或者说final局部变量
才能被其局部内部类使用。
示例:
1) 被局部内部类使用的局部变量不管在局部内部类外还是类内都不可变:
2) 方法、构造器局部内部类示例