嵌套类(nested class)和内部类(inner class)。嵌套类是一个在另一个类或者接口内部声明的类。嵌套类有两种类型:静态内部类(static inner class)和非静态嵌套类(non-static nested class)。非静态嵌套类也被称作内部类(inner class)。
![]()





内部类有几种类型:
- 成员内部类(member inner class)
- 本地内部类(local inner class)
- 匿名内部类(anonymous inner class)
"顶层类"(top level class)一词是指没有在另一个类或者接口中进行定义的类。换句话说,顶层类的外部没有任何类把它包住。
嵌套类的行为表现类似于一个普通的(顶层)类。嵌套类可以扩展另一个类,实现接口,变成子类的父类等。
对于顶层类而言,嵌套类与其他的类成员(方法,字段)无异。嵌套类可以有4中访问修饰符:private、protected、default和public。这与顶层类不同,它只能有public和default两种修饰符。
由于嵌套类是外层类的成员,静态嵌套类的行为与内部类的行为是不完全相同的。下面是是它们之间的区别:
- 静态嵌套类可以有静态成员,内部类则不行
- 像实例方法一样,内部类可以访问外层类的静态成员和非静态成员,包括它的private成员(因为嵌套类是外层类的成员)。静态嵌套类则只能访问外层类的静态成员(因为静态嵌套类也是外层类的静态成员)。
- 不需要先创建其外层类的实例就可以直接创建静态嵌套类的实例。相反,在将内部类本身实例化之前,必须先创建一个包装内部类的外层类的实例。
- 内部类可以访问外层类的所有成员
- 内部类有助于完全隐藏一个类的实现
- 内部类提供了一种在Swing和其他基于事件的应用程序中编写监听器的快捷方法。
不需要先创建外层类的实例就可以直接创建一个静态的嵌套类。![]()
![]()
![]()

关于静态的嵌套类,有几点需要注意:
- 要用这种方式调用嵌套类:OuterClassName.InnerClassName
- 实例化静态的嵌套类时,不需要创建外层类的实例
- 必须从静态嵌套类内部访问外层类静态成员
成员内部类
成员内部类是指其定义直接被另一个类或者接口的声明包装的类。只有当其引用其外层类的实例时,才会创建成员内部类的实例。为了从外层类内部创建内部类的实例,可以调用内部类的构造器,就像调用其他普通的类一样。但是如果想要从外层类的外部创建内部类的实例,则必须使用以下语法:OuterClassName.InnerClassName
inner = outerClassObjectReference.new InnerClassName();
从内部类内部,可以用this引用其实例。要引用外层类的实例,需要这个语法:OuterClassName.this
成员内部类可以用来完全隐藏一个实现:
局部内部类
局部内部类(local inner class)或简称局部类(local class),从定义上将,它不属于任何其他类的成员类(因为它的声明不是直接在外层类的声明中)。局部类有名称,与没有名称的匿名类相反。
局部类可以在任何代码块中进行声明,它的作用域是在这个块之内:
局部类可以访问外层类的成员,还可以访问局部变量。然后,你只能访问final局部变量。如果你试图访问一个非final的局部变量,编译器将会产生一个编译错误。
匿名内部类
匿名内部类没有名称。使用这种嵌套类是为了编写接口实现。
此外,可以通过扩展一个抽象类或具体类来创建匿名的内部类:
深入了解嵌套类和内部类
JVM并不了解嵌套类的概念,是编译器在努力地将内部类编译成顶层类,以外层类和内部类的名称为名,两者之间用一个美元符号分隔。也就是说,使用一个处于Outer内部名为Inner的内部类,它们会被编译成Outer.class和Outer$Inner.class。
那么匿名内部类有如何呢?对于匿名类,编译器会尽量利用数字为它们生成一个名称。因此,你会看到像Outer$1.class、Outer$2.class等这样的名称。
当实例化嵌套类时,该实例就是堆中的一个独立对象。它实际上并不是处在外层类对象的内部。
然而,创建了内部类对象,它们就有了对外层类对象的一个自动引用。但是,这个引用不存在静态嵌套类的实例中,因为静态嵌套类不能访问其外层类的实例成员。
一个内部类对象如何获得对其外层类的引用呢?这还是因为编译器在编译内部类时稍微修改了内部类的构造器,也就是说它给每个构造器都增加了一个参数。这个参数就是外层类的类型。
例如,一个像这样的构造器:
public Inner()
改成:
public Inner(Outer outer)
这个构造器:
public Inner(int value)
改成:
public Inner(Outer outer, int value)
随着编译器将外层类对象的一个引用传递给内部类构造器,实例化内部类的代码页修改了。如果编写:
Outer outer = new Outer();
outer.Inner inner = outer.new Inner();
编译器会将它改成:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(outer);
当一个内部类在外层类内部实例化时,编译器当然会利用关键字this传递外层类对象的当前实例。
现在讲解另外一个问题。嵌套类是如何访问其外层类private成员的呢?任何对象都不允许访问另一个对象的private成员。这还是因为编译器修改了代码,它创建了一个方法,用来访问外层类定义中的private成员。因此,
被编译器修改成了:
这种添加是在编译器后台发生的,因此你在源代码是看不到。编译器添加了返回private成员值的access$0方法,因此内部类可以访问private成员。