10.8 为什么需要内部类
每个内部类都能独立的继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对内部类没有影响。内部类提供可以继承多个具体的或抽象的类的能力。
10.8.1 闭包与回调
闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来源于创建它的作用域。内部类是面向对象的闭包。
大家自己欣赏一下代码:
// 接口
interface Incrementable {
void increment();
}
// 外部类实现接口
class Callee1 implements Incrementable {
private int i = 0;
public void increment() {
i++;
System.out.println(i);
}
}
// 类
class MyIncrement {
public void increment() {
System.out.println("Other operation");
}
static void f(MyIncrement mi) {
mi.increment();
}
}
// If your class must implement increment() in
// some other way, you must use an inner class:
class Callee2 extends MyIncrement {
private int i = 0;
public void increment() {
super.increment();
i++;
System.out.println(i);
}
// 内部类实现接口
private class Closure implements Incrementable {
public void increment() {
// Specify outer-class method, otherwise you'd get an infinite recursion:
Callee2.this.increment();
}
}
// 返回实现了Incrementable类的对象
Incrementable getCallbackReference() {
return new Closure();
}
}
class Caller {
private Incrementable callbackReference;
Caller(Incrementable cbh) {
callbackReference = cbh;
}
void go() {
callbackReference.increment();
}
}
public class Callbacks {
public static void main(String[] args) {
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.f(c2);
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallbackReference());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
}
10.8.2 内部类与控制框架
设计模式总是将变化的事物与不变的事物分离开来。
10.9 内部类的继承
class WithInner {
private int i;
class Inner {
public Inner() {
System.out.println("我是内部类构造函数!");
}
}
}
public class InheritInner extends WithInner.Inner {
public InheritInner(WithInner withInner) {
// 必须加上这句话否则编译错误
withInner.super();
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner ii = new InheritInner(wi);
}
}
内部类持有外部类的引用。在继承内部类的时候,那个指向外部类对象的“秘密的”引用必须被初始化。所以必须在子类的构造器使用如下语法:
enclosingClassReference.super();
这样才提供了必要的引用,程序才可以编译通过。
10.10 内部类可以被覆盖吗
答案当然是不可以,覆盖只是针对于方法而言的。
10.11 局部内部类
局部内部类不能有访问说明符,因为他不是外部类的一部分;但是他可以访问当前代码块内的常量,以及此外部类的所有成员。
interface Counter {
int next();
}
public class LocalInnerClass {
private int count = 0;
Counter getCounter(final String name) {
// 局部内部类
class LocalCounter implements Counter {
public LocalCounter() {
// Local inner class can have a constructor
System.out.println("LocalCounter()");
}
public int next() {
System.out.println(name); // Access local final
return count++;
}
}
return new LocalCounter();
}
// The same thing with an anonymous inner class:
// 返回匿名内部类
Counter getCounter2(final String name) {
return new Counter() {
// Anonymous inner class cannot have a named
// constructor, only an instance initializer:
{
System.out.println("Counter()");
}
public int next() {
System.out.println(name); // Access local final
return count++;
}
};
}
public static void main(String[] args) {
LocalInnerClass lic = new LocalInnerClass();
Counter c1 = lic.getCounter("Local inner "),
c2 = lic.getCounter2("Anonymous inner ");
for (int i = 0; i < 5; i++)
System.out.println(c1.next());
for (int i = 0; i < 5; i++)
System.out.println(c2.next());
}
}
既然局部内部类的名字在方法外是不可见的,那为什么我们仍然使用局部内部类而不是匿名内部类呢?唯一的理由是:我们需要一个已经命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例的初始化
,所以使用局部内部类而不使用匿名内部类的另一个理由是,需要不止一个内部类对象
。局部内部类更灵活。
10.12 内部类标识符
每个类都会生成 .class 文件,那么内部类的 .class 文件叫什么名字呢?
普通内部类:外部类的名称$内部类的名称.class
匿名内部类:外部类的名称$数字.class【使用数字作为其标识符】
如果是多个内部类嵌套:外部类的名称$内部类的名称$内部类的名称… .class
每个内部类都会单独生成一个 .class 文件