引言
Java语法中允许一个类嵌套在另一个类中,我们把嵌套在其他类中的类称为内部类。而内部类又分为两种,静态内部类(static nested classes)和非静态内部类(inner classes)。
例如这样的关系:
//外部类
class OuterClass {
//静态内部类
static class StaticNestedClass {
...
}
//非静态内部类
class InnerClass {
...
}
}
内部类是外部类的一个成员。
非静态内部类可以直接调用外部类的其他成员。
而静态内部类不可以直接调用外部类的其他成员。
为什么要使用内部类
1.如果一个类A只为另一个类B服务,那把A嵌套在B中,就相当于B的一个服务类,代码可读性更高,方便维护。
2.如果一个类A要调用另一个类B,但B又不想被其他类所引用就要申明为private,那把A嵌套在B中,就可以同时满足前面的两个要求了,代码的封装性更好了。
静态内部类
静态内部类可以直接调用外部类的静态成员(静态成员变量和静态方法),但是不能直接调用外部类的非静态成员。
静态内部类的使用
1.直接通过类名调用:
OuterClass.StaticNestedClass
2.创建实例 :
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
其实我们可以把静态内部类看成和外部类平级的一个类,我们在调用静态内部类时甚至都不用初始化外部类。
如下是一个外部类People和嵌套在其中的静态内部Man。
public class People {
static String hi = "I'm People";
static {
System.out.println("People的static代码块");
}
People() {
System.out.println("People的构造方法");
}
static class Man {
static String hello = "I'm Man";
static {
System.out.println("Man的static代码块");
}
Man() {
System.out.println("Man的构造方法");
}
}
}
调用代码:
public static void main(String[] args) {
People.Man man = new People.Man();
}
运行结果:
Man的static代码块
Man的构造方法
显然在创建静态内部类实例的时候,外部类根本就没有被初始化。
非静态内部类
只有创建了外部类的实例才能使用非静态内部类,所以非静态内部类不允许存在静态成员。
然后根据外部类的实例就可以创建非静态内部类实例,并且非静态内部类实例持有了外部类的引用
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
同名变量的覆盖问题
来看一个覆盖测试:
public class ShadowTest {
public int x = 0;
class FirstLevel {
public int x = 1;
void methodInFirstLevel(int x) {
System.out.println("x = " + x);
System.out.println("this.x = " + this.x);
System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
}
}
public static void main(String... args) {
ShadowTest st = new ShadowTest();
ShadowTest.FirstLevel fl = st.new FirstLevel();
fl.methodInFirstLevel(23);
}
}
测试结果:
x = 23
this.x = 1
ShadowTest.this.x = 0
通过以上结果显然可以知道:
如果内部类的局部变量和内部类的成员变量以及外部类的成员变量重名为x。
那么内部类的局部变量就是x,
内部类的成员变量用this.x表示,
外部类的成员变量用外部类名.x表示。
序列化的问题
Oracle官方强烈不建议序列化非静态内部类,包括局部内部类和匿名内部类,因为Java编译器为了编译内部类和一些其他东西,采用了虚拟构建方法。虚拟构建方法使Java编译器实现了Java新特性而不用修改Java虚拟机。但是Java编译器实现的不同会导致虚拟构建方法的不同,这就意味着你在一个JRE中序列化了一个内部类,在另一个JRE中反序列化它时会遇到兼容性问题。