目录
在类中定义的类称为内部类,内部类又可以分为成员内部类(实例内部类、静态内部类)、局部内部类、匿名内部类等。
一、成员内部类
成员内部类:在一个类中,与类成员变量、方法同级别的类,可以称为成员内部类。
实例内部类
public class Main {
public static void main(String[] args) {
Outer outer = new Outer("Outer"); // 实例化一个Outer
Outer.Inner inner = outer.new Inner(); // 实例化一个Inner
inner.hello();
}
}
class Outer { // 定义一个外部类
private String name;
Outer(String name) {
this.name = name;
}
class Inner { // 定义一个内部类
void hello() {
System.out.println("Hello, " + Outer.this.name);
}
}
}
Outer
是一个外部类,而Inner
是一个内部,它与外部类有个最大的不同,就是内部类的实例不能单独存在,必须依附于一个外部类的实例。
静态内部类
public class Main {
public static void main(String[] args) {
Outer.StaticNested sn = new Outer.StaticNested();
sn.hello();
}
}
class Outer {
private static String NAME = "OUTER";
private String name;
Outer(String name) {
this.name = name;
}
static class StaticNested {
void hello() {
System.out.println("Hello, " + Outer.NAME);
}
}
}
用static修饰的内部类不依附于外部的实例,而是一个完全独立的类,因此无法引用外部类.this,但它可以访问外部类的private静态字段和静态方法。
二、局部内部类
局部字面意思范围,例如在方法范围的类,就是一个局部内部类。
public class Main {
public static void main(String[] args) {
Outer outer = new Outer("Outer");
outer.outerMethod();
}
}
class Outer {
static String name; // 内部类可以访问,
public Outer(String name){
this.name = name;
}
void outerMethod() {
class Inner {
public void innerMethod() {
System.out.println(name);
}
}
Inner n = new Inner();
n.innerMethod();
}
}
局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。
局部内部类只在当前方法中有效。
三、匿名内部类
匿名内部类:可以理解为隐藏了名字的内部类。
public class Main {
public static void main(String[] args) {
Outer outer = new Outer("Outer"); // 实例化一个Outer
outer.asyncHello();
}
}
class Outer { // 定义一个外部类
private String name;
Outer(String name) {
this.name = name;
}
void asyncHello() {
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello, " + Outer.this.name);
}
};
new Thread(r).start();
}
}
在asyncHello()
方法中,方法内部实例化了一个Runnable
。Runnable
本身是接口,接口是不能实例化的,所以这里实际上是定义了一个实现了Runnable
接口的匿名类,并且通过new
实例化该匿名类,然后转型为Runnable
。在定义匿名类的时候就必须实例化它,定义匿名类的写法如下:
Runnable r = new Runnable() {
// 实现必要的抽象方法...
};
匿名类也完全可以继承自普通类
public class Main {
public static void main(String[] args) {
HashMap<String, String> map1 = new HashMap<String, String> ();
HashMap<String, String> map2 = new HashMap<String, String> () {}; // 匿名类!
HashMap<String, String> map3 = new HashMap<String, String> () {
{
put("A", "1");
put("B", "2");
}
};
System.out.println(map3.get("A"));
}
}
map1
是一个普通的HashMap
实例,但map2
是一个匿名类实例,只是该匿名类继承自HashMap
。map3
也是一个继承自HashMap
的匿名类实例,并且添加了static
代码块来初始化数据。观察编译输出可发现Main$1.class
和Main$2.class
两个匿名类文件。