嵌套类分为两类:静态和非静态。被声明static的嵌套类称为静态嵌套类。非静态嵌套类称为内部类。
内部类有两种特殊的内部类: 本地类和 匿名类。
为什么使用嵌套类:
- 这是一种逻辑分组的方法,它只在一个地方使用:如果一个类只对另一个类有用,那么将它嵌入该类并将它们保持在一起是合乎逻辑的。嵌套这样的“帮助类”使得它们的包更加简化。
- 它增加了封装:考虑两个顶级类A和B,其中B需要访问否则将被声明的A成员private。通过在类A中隐藏类B,可以将A的成员声明为私有,并且B可以访问它们。另外,B本身可以被外界隐藏起来。
- 它可以导致更易读和可维护的代码:在顶级类中嵌套小类会使代码更接近它的使用位置。
1.静态嵌套类
与类方法和变量一样,静态嵌套类与其外部类相关联。像静态类方法一样,静态嵌套类不能直接引用其封闭类中定义的实例变量或方法:它只能通过对象引用来使用它们。
注意: 静态嵌套类与其外部类(和其他类)的实例成员交互,就像任何其他顶级类一样。实际上,为了方便打包,静态嵌套类在行为上是嵌套在另一个顶级类中的顶级类。
public class OuterClass {
static class StaticClass{
public void test(){
System.out.println("static class test");
}
}
public static void main(String[] args) {
OuterClass.StaticClass t = new OuterClass.StaticClass();
t.test();
}
}
2.内部类
与实例方法和变量一样,内部类与其包含类的实例关联,并可直接访问该对象的方法和字段。另外,因为内部类与一个实例相关联,所以它不能自己定义任何静态成员。
一个实例InnerClass只能存在于一个实例中,OuterClass并且可以直接访问其封装实例的方法和字段。
要实例化一个内部类,你必须首先实例化外部类。然后,使用以下语法在外部对象内创建内部对象:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
序列化
内部类的序列化,包括 本地和 匿名类,强烈不鼓励。当Java编译器编译某些结构(如内部类)时,它会创建合成结构 ; 这些是在源代码中没有相应构造的类,方法,字段和其他构造。合成结构使Java编译器能够在不改变JVM的情况下实现新的Java语言功能。但是,合成结构可以在不同的Java编译器实现中有所不同,这意味着.class
文件也可以在不同的实现中有所不同。因此,如果序列化内部类,然后使用不同的JRE实现对其进行反序列化,则可能会遇到兼容性问题
2.1 普通内部类
public class OuterClass {
public String o = "outer";
private InnerClass inner = new InnerClass();
public void test(){
System.out.println("outer class test: "+inner.i);//inner
}
//内部类
class InnerClass{
public String i = "inner";
public void test(String i){
System.out.println("inner class test: "+i);//test_i
System.out.println("inner class test: "+this.i);//inner
System.out.println("inner class test: "+o);//outer
System.out.println("inner class test: "+OuterClass.this.o);//outer
}
}
public static void main(String[] args) {
OuterClass o = new OuterClass();
o.test();
OuterClass.InnerClass i = o.new InnerClass();
i.test("test_i");
}
}
2.2 本地类
本地类是在块中定义的类,它是平衡花括号之间的一组零个或多个语句。您通常会在方法的主体中找到定义的本地类。
- 一个本地类可以访问其封闭类的成员。
- 本地类可以访问局部变量。但是,本地类只能访问声明为最终的局部变量。
public class OuterClass {
public String o = "outer";
public void test(){
System.out.println("outer class test");
final String local = "outer local";
//本地类
class LocalInnerClass{
public String i = "local inner";
public void test(String i){
System.out.println("local inner class test: "+i);//param_i
System.out.println("local inner class test: "+this.i);//local inner
System.out.println("local inner class test: "+o);//outer
System.out.println("local inner class test: "+local);//outer local
System.out.println("local inner class test: "+OuterClass.this.o);//outer
}
}
LocalInnerClass li = new LocalInnerClass();
li.test("param_i");
}
public static void main(String[] args) {
OuterClass o = new OuterClass();
o.test();
}
}
2.3 匿名类
匿名类使您能够使代码更加简洁。它们使您能够同时声明和实例化一个类。除了没有名字之外,它们就像本地的课程。如果您只需要使用一次本地课程,请使用它们。
虽然本地类是类声明,但匿名类是表达式,这意味着您可以在另一个表达式中定义该类。
public class OuterClass {
public String o = "outer";
interface TestInterface {
public void test();
}
public void test(){
final String local = "outer local";
TestInterface ti = new TestInterface() {
public String t = "anonymous";
@Override
public void test() {
System.out.println("test anonymous class: "+o);
System.out.println("test anonymous class: "+local);
System.out.println("test anonymous class: "+t);
}
};
ti.test();
}
public static void main(String[] args) {
OuterClass o = new OuterClass();
o.test();
}
}
匿名类通常用于图形用户界面(GUI)应用程序。如添加事件处理。