Java内部类的作用:
1)可以隐藏代码中的细节:一般的类智能为public,内部类可以为private、protected,实现隐藏
2)方便调用外部类的成员变量:内部类拥有外部类的this指针
3)便于实现多重继承:
class M {}
class N {}
class P {
class P1 extends M{}
class P2 extends N{}
}
一、内部类生成class文件情况:
public class A {
class C {
class G{}
}
static class D {}
void a () {
// 注意:方法中的内部类的class文件格式与别的不同
class E{}
}
interface F {}
abstract class H {}
}
class B {}
生成的class文件:
二、内部类问题:
public class A {
class B {}
static class C {}
// 在静态方法中,由于没有this指针,初始化时不能直接使用B的构造函数
/**== 即构建内部类对象时,需要一个指向其外围类对象的引用,内部类对象会链接到该外部类对象上。所以应当首先创建外部类对象;
* 而对于嵌套类(静态内部类),则不需要该引用 ==**/
public static void a() {
// 由于B是非static的,访问其需要通过初始化A的实例进行使用
A aa = new A();
B bb = aa.new B();
// 因为C也是静态内部类,所以可以直接用其构造函数
C cc = new C();
}
// 在非静态方法中的初始化较为简单
public void b() {
B b = new B();
C cc = new C();
}
}
// 注意在外部类中的初始化方法与A类中的不同
class E {
public void m() {
A a = new A();
// 声明需要完整的OutClass.InnerClass格式
A.B b = a.new B(); // 非静态类的初始化
A.C c = new A.C(); // 静态类的初始化
}
}
构建内部类对象时,需要一个指向其外围类对象的引用,内部类对象会链接到该外部类对象上,所以应当首先创建外部类对象;
而对于嵌套类(静态内部类),则不需要该引用。
而因为内部类对象保存了对外部类对象的引用,故可以访问外部类中的所有成员变量及方法;
三、局部内部类:
局部内部类:定义在方法或者任意作用域中的类;它只是方法的一部分,而不是外部类的一部分。
1)局部内部类的生命周期问题:局部内部类的生命周期并不会随着方法的结束而结束;
public class A {
class B {
public void printData() {
System.out.println("B");
}
}
public B a() {
class C extends B{
@Override
public void printData() {
System.out.println("C");
}
}
// 这里实例化C对象,并向上转化为其父类B
return new C();
}
public void printData() {
a().printData();
}
public static void main(String[] args) {
new A().printData();
}
}
最后输出的结果为“C”,可以看到C的生命周期并未结束。
2)使用外部变量需用final进行修饰的问题:
public class A {
class B {
public void printData() {
System.out.println("B");
}
}
String outerClass_data = "outerClass_data";
public B a(final String parameter_data) {
final String outerMethod_data = "outerMethod_data";
class C extends B{
@Override
public void printData() {
/** 可以看到因为生命周期的原因,parameter_data与outerMethod_data的生命周期较短;
* 故需要使用final对其进行修饰 **/
System.out.println(outerClass_data);
System.out.println(outerMethod_data);
System.out.println(parameter_data);
}
}
// 这里实例化C对象,并向上转化为其父类B
return new C();
}
public void printData() {
String data = "data";
a(data).printData();
}
public static void main(String[] args) {
new A().printData();
}
}
该外部变量必须使用final进行修饰是因为生命周期的原因,因为方法内部变量,或者形参,其生命周期是与方法相同的;而前面也提到局部内部类的生命周期并不会因为方法的结束而结束;即方法局部变量与局部内部类的生命周期不同;当方法结束后,就会出现局部内部类非法引用已经销毁的局部变量的情况;
因而虚拟机采用的做法是使用final进行修饰该变量,在编译局部内部类时,会在局部内部类内部生成一个该final变量的拷贝,从而解决生命周期的问题。
四、匿名内部类 实现继承:
1)匿名内部类的定义:
public class A {
class B {
public void printData() {
System.out.println("B");
}
}
String outerClass_data = "outerClass_data";
public B a(final String parameter_data) {
final String outerMethod_data = "outerMethod_data";
// 定义一个匿名内部类
return new B() {
@Override
public void printData() {
/** 可以看到因为生命周期的原因,parameter_data与outerMethod_data的生命周期较短;
* 故需要使用final对其进行修饰 **/
System.out.println(outerClass_data);
System.out.println(outerMethod_data);
System.out.println(parameter_data);
}
};
}
public void printData() {
String data = "data";
a(data).printData();
}
public static void main(String[] args) {
new A().printData();
}
}
其实上面局部内部类的用法可以精简地写成匿名内部类的形式:匿名内部类表示创建一个集成自B的一个匿名类对象,并且通过new表达式将返回的引用自动向上转型为B的引用。
因而局部内部类对final变量的要求对于匿名内部类同样适用;
2)带参数初始化的匿名内部类:
public class A {
class B {
public B(int i) {}
public void printData() {
}
}
public B a() {
// 定义一个匿名内部类
return new B(100) {
@Override
public void printData() {
}
};
}
}
3)局限性:匿名内部类相对于正常的继承,它可以实现继承类,也可以实现接口;当两个同一时刻只能实现一种;即是是实现接口,也只能实现一个接口;