首页 > 代码库 > Java基础:内部类

Java基础:内部类

在某些情况下,把一个类放在另一个类的内部定义,这个定义在其他类内部的类就称为内部类。包含内部类的类被称为外部类。内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。

根据类定义的位置和修饰符的不同,内部类可以分为:

  • 成员内部类(包括静态成员内部类,非静态成员内部类)

  • 方法内部类

  • 匿名内部类


1 静态成员内部类

1.1 定义

package com.demo;

public class Outer {
	private static String name = "Outer";
	private int i = 5;

	public void accessInnerProp() {
		System.out.println("---------accessInnerProp()-------");

		System.out.println(Inner.name);

		Inner inner = new Inner();
		System.out.println(inner.i);
	}

	public static class Inner {
		private static String name = "Inner";
		private int i = 6;

		public void sayHello() {
			System.out.println("---------sayHello()-------");
			System.out.println(name);
			System.out.println(this.name);
			System.out.println(Outer.name);
		}
	}
}
package com.demo;

public class Test {

	public static void main(String[] args) {
		Outer.Inner in = new Outer.Inner();
		in.sayHello();

		Outer out = new Outer();
		out.accessInnerProp();
	}

}

输出结果:

---------sayHello()-------
Inner
Inner
Outer
---------accessInnerProp()-------
Inner
6

1.2 特性

如果使用static修饰一个内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象。

因为内部类作为其外部类的成员,所以可以使用任意访问控制符,如private、protected、缺省和public等修饰。

静态成员内部类可以包含静态成员,也可以包含非静态成员(例如,示例中Inner内部的name和sayHello( ))。

内部类访问外部类。根据静态成员不能访问非静态成员的规则,静态成员内部类不能访问外部类的实例成员,只能访问外部类的类成员。即使是静态成员内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员(例如,示例中内部类Inner不能访问实例成员 i )。

在外部类内使用内部类。外部类不能直接访问静态内部类的成员,但可以直接使用静态内部类的类名作为调用者来访问静态成员内部类的静态成员,也可以直接使用静态成员内部类的类名定义内部类对象,以该内部类对象作为调用者来访问静态成员内部类的实例成员(例如,Outer类中accessInnerProp( )方法)。

在外部类之外使用内部类。因为静态成员内部类是与外部类相关的,因此创建内部类对象时,无须创建外部类对象。在外部类之外使用内部类的格式为:“外部类.内部类”,例如:

Outer.Inner in = new Outer.Inner();
public class InnerSubClass extends Outer.Inner {
}

1.3 本质

从技术上讲,静态成员内部类不属于内部类,只是它在一个类内部的内部定义,导致每次在外部类之外使用类,类名都必须加上一个"外部类类名."作为限制。当定义一个静态内部成员类时,其外部类非常像一个包空间。

示例代码编译后,生成Outer.class和Outer$Inner.class。

反编译Outer$Inner.class:

javap -c Outer$Inner.class > oi.txt

字节码:

技术分享

从反编译结果可以看出:

  • 静态成员内部类的类名是“外部类$内部类”;

  • 编译器自动在内部类的class文件中添加了静态方法,用来访问内部类的各种Field,命名格式为“access$N”。外部类使用静态成员内部类成员时(例如,accessInnerProp( )方法),每处Field调用都被编译器替换为相应的方法。

  • 静态成员内部类的字节码与普通的字节码大体相同,再次验证:外部类对于静态成员内部类而言,只是多了一层作用域,类似于包的作用,其他与普通类基本无异。


2 非静态成员内部类

1.1 定义


1.2 特性


1.3 本质

3 方法内部类

1.1 定义


1.2 特性


1.3 本质


4 匿名内部类

1.1 定义


1.2 特性


1.3 本质

5 内部类的意义


Java基础:内部类