一、什么是嵌套类
嵌套类是任意声明在另一个类或接口中的类,最外层的类不是嵌套类。通常可将嵌套类分为两种:静态嵌套类和内部类。如下:
class OuterClass {
...
class NestedClass {
...
}
}
嵌套类可以分为两种,静态的和非静态的,即静态嵌套类和非静态嵌套类。非静态嵌套类又叫做内部类(Inner Class)。
class OuterClass {
...
class InnerClass {
...
}
static class StaticNestedClass {
...
}
}
上述代码中InnerClass就是内部类,staticNestedClass就是静态嵌套类。
二、内部类
比如有如下内部类的定义
class OuterClass {
...
class InnerClass {
...
}
}
OuterClass是InnerClass的外围类,InnerClass是OuterClass的内部类。内部类的实例对象都会绑定一个外围类的实例对象,并且InnerClass可以访问其所绑定的OuterClass的所有成员属性和方法,包括私有成员属性和方法。在InnerClass中通过OuterClass.this显式地引用其所绑定的OuterClass的实例。要实例化InnerClass,必须首先实例化其外围类OuterClass,然后通过如下的语法创建内部类的实例。
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
注意,上面写的是outerobject.new InnerClass(),而不是new OuterClass.InnerClass();我们在执行代码OuterClass.InnerClass innerObject=outerobject.new InnnerClass()的时候,其实做了两件事。一件事是创建了一个内部类的实例innerObject,第二件事是让innerObject绑定outerObject作为其外围类的实例。这样innerObject就可以访问outerObject内的所有成员属性以及方法了。
三、为什么要使用内部类
1.实现多重继承
Java中并没有提供多重继承,内部类可以实现多重继承。每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。
2.内部类可以有多个实例,每一个实例有独立的状态信息。
3.在一个外部类中可以有多个内部类,并且每个内部都可以实现同一个接口或者继承同一个类,但是它们的内部实现不同。
4.内部类可以“按需创建”。
5.内部类并不存在is-a的关系,每一个内部类都是一个独立的实体。
四、静态嵌套类
有些人把静态嵌套类成为静态内部类,其实静态内部类这个称呼不严谨,因为内部类都是非静态的。静态嵌套类与内部类有很大的不同,静态嵌套类说到底就是一个静态类,只不过是其位置位于某个类的内部罢了。
假设有如下静态嵌套类的定义:
class OuterClass {
...
static class StaticNestedClass {
...
}
}
那么我可以像正常使用一个一般的静态类那样使用一个静态嵌套类,只不过要通过其外围类的名字来访问静态嵌套类的名字。所以,外围类更像是静态嵌套类的命名空间。比如要获取静态嵌套类,要使用OuterClass.StaticNestedClass。
如果要创建静态嵌套类的实例对象,使用如下的语法:
OuterClass.StaticNestedClass nestedObject=new OuterClass.StaticNestedClass();
由于静态嵌套类的本质就是一个静态类,所以其实例对象的初始化不需要也不能像内部类那样需要绑定一个外围类对象。静态嵌套类内部可以定义静态属性、静态方法。静态嵌套类内部不能访问外部类的非静态变量,非静态方法。同时外部类不能直接访问静态嵌套类的成员变量,可以通过静态嵌套类来访问。
综上所述,虽然内部类和静态嵌套类都属于嵌套类,但是二者有本质区别:内部类的实例化需要绑定一个外围雷达实例化对象,而静态嵌套类的实例化对象不能也无法绑定外围类的实例化对象。