介绍
内部类(Inner Class)或内部接口(Inner Interface),是定义在一个类中的成员。相对的,这个内部类外的类被称为外部类;和外部类并列的类被称为“其它类”。这里的内部类,其官方名称为嵌套类(Nested Class),包含静态嵌套类(又称“静态内部类”)和非静态嵌套类(又称“内部类”)两种。
- 内部类和外部类能够更好地表现这两个类间的逻辑性。
内部类和普通类同样,在编译后产生同样的.class字节码文件,但在命名上有所不同,为“外部类名$内部类名.class”。
成员内部类
class Outer {
class Inner {
}
}
成员内部类是外部类的一个成员。和成员变量一样,使用成员内部类需要先实例化一个对象才能使用。成员内部类有如下特点:
成员内部类不能定义静态成员和静态方法。
- 成员内部类和其它类差不多,可以正常地继承、实现,并且也可以具有内部类和内部接口。
- 内部类和外部类自己可以相互使用对方的成员和方法,无论是不是私有的。在内部类中使用外部类成员和方法时,需要使用this先实例化一个外部类对象。
其它类若要使用一个类的成员内部类时,需要先导包,并实例化外部类对象后才能使用这个内部类。
静态内部类
class Outer {
static class Inner {
static int A;
}
}
静态内部类是使用static修饰的内部类。静态内部类有以下特点:
静态内部类是属于类的。和其它静态代码一样,可以使用类名直接访问静态内部类;也可以通过对象间接访问。
- 和其它内部类不同,静态内部类可以定义静态成员和静态方法。
- 静态内部类中,无法访问外部类的非静态属性和方法。
其它类若要使用一个类的静态内部类时,需要先导包,然后即可直接使用类名创建静态内部类对象。且只能使用类名访问,不能使用外部类对象访问。
局部内部类
class Outer {
void A() {
class Inner {
}
}
}
局部内部类是在外部类的方法中定义的类,只能被方法中的代码访问和调用。局部内部类有以下特点:
局部内部类中的方法不能使用外部方法的同名参数。局部内部类不能定义静态成员和静态方法。
- 局部内部类访问外部类的成员变量需为一个final常量(或仅被赋值一次的变量)。
- 局部内部类只能在当前方法中被使用,外部类和其他类只能通过调用方法间接使用。
- 其.class文件的命名为“外部类名$1内部类名.class”,其中1为序号,以识别外部类名和内部类名都相同的类。
匿名内部类
匿名内部类是对接口的实现的一个简便方式。同时,也可以对父类(一般是个抽象类)的方法(一般是个抽象方法)进行重写:interface If {
void p();
}
class Test {
void main() {
If if = new If() { // 同时在这里也是一个局部内部类,只能使用final外部类成员变量
void p() {
;
}
};
if.p();
}
}
其方法是用一个接口(或抽象类)的引用指向其“无参构造器”(但并没有创建接口的对象),同时在后面用一个大括号括起一个类的内容。因为匿名内部类没有类名,故只能通过这种方式创建仅一次对象,且匿名内部类中无法定义构造器。其.class文件的命名为“外部类名$1.class”,其中1为序号。class Father {
void p();
}
class Test {
void main() {
Father f = new Father() {
void p() {
;
}
};
f.p();
}
}
内部类的对比
- 所有的内部类都具有独立的.class字节码文件。
- 成员内部类和静态内部类与外部类之间可以相互访问(包括私有);局部内部类和匿名内部类可以访问外部类,但外部类只能在当前方法中访问这两种类。
- 其它类要访问成员内部类和静态内部类需要导包(外部类全类名.内部类),前者通过对象调用,后者通过类名调用。所有私有代码均无法访问。
内部类 | 定义 | 静态代码 | 非静态代码 | .class字节码文件 | ||
---|---|---|---|---|---|---|
包含/访问外部 | 被调用 | 访问外部 | 被调用 | |||
成员内部类 | 定义在类中的成员,和成员变量概念相当 | 不能包含,访问: 类名.变量 |
N/A | 自己类:this.成员 外部类:外部类.this.成员 其他类:其他类对象引用.成员 |
自己类:this.成员 外部类:new 内部类对象.成员 其他类:导包,new 外部类对象.new 内部类对象.成员 |
.Father$Son |
静态内部类 | 被static修饰的成员内部类 | 可以包含,访问: 自己类:变量 外部类和其他类:类名.变量 |
自己类:变量 外部类:类名.变量 或 对象.变量 外部类:导包,类名.变量 或 对象.变量 |
自己类:this.成员 外部类和其他类:N/A |
同成员内部类 | .Father$Son |
局部内部类 | 定义在方法中的类,和局部变量相当 | 同成员内部类 | N/A | 自己类:this.成员 外部类: 外部类.this.成员 当前方法:final修饰的常量 其他类:其他类对象引用.成员 |
自己类:this.成员 外部类:只在本方法中,new 内部类对象.成员 其他类: N/A |
.Father$1Son |
匿名内部类 | 没有类名的局部内部类 | 同成员内部类 | N/A | 同局部内部类 | 同局部内部类 | .Father$1 |
内部类的选择
假设现在已经确定了要使用内部类,那么一般情况下,该如何选择?
1. 考虑这个内部类,如果需要反复的进行多次使用(必须有名字)
- 在这个内部类中,如果需要定义静态的属性和方法,选择使用静态内部类
- 在这个内部类中,如果需要访问外部类的非静态属性和方法,选择使用成员内部类
- 考虑这个内部类,如果只需要使用一次(可以没有名字)
- 选择使用匿名内部类
- 局部内部类,几乎不会使用
以下是一个代码补充题(我觉得这题出得很好):
interface Inter{
public abstract void method();
}
class InnerClassDemo2 {
public static void main(String[] args){
Test.function().method(); //分析此语句的实现功能。
//1. 该语句通过类名Test直接调用,故function应为一个static方法
//2. 方法调用后还能够调用方法,故该方法应有具有返回值,且是一个对象
//3. 该对象具有一个方法method(),并具有一个匿名内部类来重写接口的方法
//故整句的功能即:运行Test类的静态function方法以创建一个Test对象,并调用method方法中的匿名内部类重写接口Inter的method方法
}
}
class Test {
//题目:通过匿名内部类补足该类代码
static Test function() {
retern new Test();
}
void method() {
new Inter() {
public void method() {}
}.method();
}
//补充完毕
}