嵌套类(nested class)指被定义在一个类的内部的类。
嵌套类有四种:
- 静态成员类
- 非静态成员类
- 局部类
- 匿名类
除了静态成员类外的三种又被称为内部类。
嵌套类存在的目的是为外围类(enclosing class)提供服务。通常基于下列原因使用嵌套类。
- 内部类的方法可以访问 外围类的的数据包括私有数据。
- 内部类可以对同一包中的其他类隐藏起来。
- 使用匿名内部类可以定义一个代码简洁的回调函数。
- 实现多继承。
避免修改接口而实现同一个类中两种同名方法的调用。
使用嵌套类的好处可以命名控制和安全控制。
一. 如果一个嵌套类不需访问外围类的实例,可以定义为静态成员类。
静态成员类可以访问外围类的静态域和方法。
公有的静态嵌套类对象创建:
EnclosingClass.MemberClass clazz = new EnclosingClass.MemberClass();
非公有的静态嵌套类,只能在外围类内部使用;通常实现一个接口,通过外围类的一个方法返回它的实例。例如 Collections类有个私有静态成员类:
static class UnmodifiableList<E> extends UnmodifiableCollection<E> implements List<E> {...};
public static <T> List<T> unmodifiableList(List<? extends T> list) {
return (list instanceof RandomAccess ?
new UnmodifiableRandomAccessList<>(list) :
new UnmodifiableList<>(list));
}
二. 如果一个嵌套类需要访问外围类的实例,可以定义为非静态成员类。非静态成员类的实例拥有一个外围类实例的引用。
公有非静态成员类的对象创建:
EnclosingClass.MemeberClass clazz = new EnclosingClass().new MemeberClass();
私有的非静态成员类,只能在外围类内部使用;通常实现一个接口,通过外围类的一个实例方法返回它的实例。不能通过外围类的一个静态方法返回它的实例。
例如 ArrayList 有一个私有的非静态成员类 Itr:
private class Itr implements Iterator<E> {...}
public Iterator<E> iterator() {
return new Itr();
}
也可以通过enclosingInstance.new MemberClass()来创建一个非静态成员类的实例。
三. 局部内部类的作用域在方法内部。限定符只能是final or abstract。
和其他嵌套类一样,局部内部类可以访问外围类和方法本地变量。Java 7中, 只能访问final本地变量。
四. 匿名内部类。
只创建这个类的对象,没有类名,通常是实现一个接口。
Runnable runnable = new Runnable(){
public void run(){
System.out.println("Hi");
};
};
new Thread(runnable).start();
示例: 如果一个类已有个方法,它需要实现一个接口,接口有同名方法,可以用嵌套类解决方法同名问题。
接口Incrementable 有一个方法increment();
interface Incrementable {
void increment();
}
类 Callee 有同样的方法 increment()
class Callee {
private int i = 0;
void incr() {
i++;
System.out.println(i);
}
void increment() {
System.out.println("MyIncrement.increment()");
}
}
如果类Callee 需要实现 Incrementable 接口,将出现重复的increment()方法,可以使用嵌套类解决这个问题:
class Callee {
private int i = 0;
void incr() {
i++;
System.out.println(i);
}
void increment() {
System.out.println("MyIncrement.increment()");
}
private class Closure implements Incrementable {
public void increment() {
incr();
}
}
public Incrementable getCallBackReference() {
return new Closure();
}
public static void main(String[] args) {
Callee callee = new Callee();
callee.increment();
callee.getCallBackReference().increment();
}
}
上面的例子就是内部类的Adapter模式。