转载自:http://www.gootry.com/java-base/article/100919202319/330
我们已经看到了许多描述内部类的语法和语义,但是这并不能回答“为什么需要内部类”这个问题。
那么,Sun公司为什么会如此费心地增加这项基本的语言特性呢?
一般说来,内部类继承自某个类或实现某个接口,内部类的代码操作创建它的外围类的对象。
所以可以认为内部类提供了某种进入其外围类的窗口。
内部类必须要回答的一个问题是:如果只是需要一个对接口的引用,为什么不通过外围类实现那个接口呢?
答案是:“如果这能满足需求,那么就应该这样做。”
那么内部类实现一个接口与外围类实现这个接口有什么区别呢?答案是:后者不是总能享用到接口带来的方便,有时需要用到接口的实现。
所以,使用内部类最吸引人的原因是:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
如果没有内部类提供的、可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。
从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。
也就是说,内部类允许继承多个非接口类型(译注:类或抽象类)。
为了看到更多的细节,让我们考虑这样一种情形:即必须在一个类中以某种方式实现两个接口。
由于接口的灵活性,您有两种选择:使用单一类,或者使用内部类:
//: innerclasses/MultiInterfaces.java
// Two ways that a class can implement multiple interfaces
package innerclasses;
interface A {}
interface B {}
class X implements A, B {}
class Y implements A {
B makeB() {
// Anonymous inner class:
return new B() {};
}
}
public class MultiInterfaces {
static void takesA(A a) {}
static void takesB(B b) {}
public static void main(string[] args) {
X x = new x();
Y y = new Y();
takesA(x);
takesA(y);
takesB(x);
takesB(y.makeB());
}
}
当然,这里假设在两种方式下的代码结构都确实有逻辑意义。
然而遇到问题的时候,通常问题本身就能给出某些指引,告诉您是应该使用单一类,还是使用内部类。
但如果没有任何其他限制,从实现的观点来看,前面的例子并没有什么区别,它们都能正常运作。
如果拥有的是抽象的类或具体的类,而不是接口,那就只能使用内部类才能实现多重继承。
//: innerclasses/MultiImplementation.java
// With concrete or abstract classes.inner
// classes are the only way to produce the effect
// of "multiple implementation inheritance."
package innerclasses;
class D {}
abstract class E {}
class Z extends D {
E maKeE() {return new E() {};}
}
public class MultiImplementation {
static void takesD(D d) {}
static void takesE(E e) {}
public static void main(String[] args) {
Z z = new Z();
takesD(z);
takesE(z.makeE());
}
}
如果不需要解决“多重继承”的问题。那么自然可以用别的方式编码,而不需要使用内部类。
但如果使用内部类,还可以获得其他一些特性:
一、内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立。
二、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类。
三、创建内部类对象的时刻并不依赖于外围类对象的创建。
四、内部类并没有令人迷惑的“is-a”关系;它就是一个独立的实体。
举个例子,如果Sequence.java不使用内部类,就必须声明“Sequence是一个Selector”,对于某个特定的Sequence只能有一个Selector。
然而使用内部类很容易就能拥有另一个方法reverseSelector(),用它来生成一个反方向遍历序列的Selector。只有内部类才有这种灵活性。