您的位置:首页 > 其它

为什么需要内部类?

2013-08-24 13:25 218 查看
你已经看到了许多描述内部类的语法和语义,但是这并不能说明“为什么需要内部类?”。
那么,Sun 公司为什么会如此费心地增加这项基本的语言特性呢?

典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外围类
的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。

内部类必须要回答一个问题是:如果我只是需要一个对接口的引用,为什么我不通过外围
类实现那个接口呢?答案是:“如果这能满足你的需求,那么你就应该这样做。”那么内
部类实现一个接口与外围类实现这个接口有什么区别呢?答案是你不是总能享用到接口带
来的方便,有时你需要与接口的实现进行交互,所以使用内部类最吸引人的原因是:

每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承
了某个(接口的)实现,对于内部类都没有影响。

如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很
难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,
而内部类有效地实现了“多重继承”。也就是说,内部类允许你继承多个非接口类型(译
注:类或抽象类)。

为了看到更多的细节,考虑下面这种情形,你必须在一个类中以某种方式实现两个接口。
由于接口的灵活性,你有两种选择:只使用单一的一个类,或者使用一个内部类:

//:c08:MultiInterfaces.java

// Two waysthat a class can implement multiple interfaces.

interface A {}
interface B {}

class X
implements A, B {}

class Y
implements A {
B makeB() {
// Anonymousinner 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());
}
} ///:~

当然,这里假设在两种方式下的代码结构都确实有逻辑意义。通常遇到问题的时候,问题
本身就能给出某些指引,告诉你应该使用单独一个类,或是使用内部类。但如果没有任何
其它限制,从实现的观点来看,前面的例子并没有什么区别。它们都能正常运作。

如果要继承的是抽象的类或具体的类,而不是接口,那你就只能使用内部类才能实现多重
继承。

//:c08:MultiImplementation.java
// Withconcrete or abstract classes, inner
// classes arethe only way to produce the effect
// of"multiple implementation inheritance."
package c08;

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());
}
} ///:~

如果不需要解决“多重继承”的问题,你自然可以用别的方式编码,而不需要使用内部类。
但如果使用内部类,你还可以获得其他一些特性:

1. 内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对
象的信息相互独立。
2. 在单个外围类中,你可以让多个内部类以不同的方式实现同一个接口,或继
承同一个类。稍后就会展示一个这样的例子。
3. 创建内部类对象的时刻并不依赖于外围类对象的创建。
4. 内部类并没有令人迷惑的“is-a”关系;它就是一个独立的实体。

举个例子,如果Sequence.java 不使用内部类,你就必须要声明“Sequence 是一个
Selector”,对于一个特定的 Sequence 只能有一个 Selector。然而使用内部类你可以很
容易地就拥有另一个方法 getRSelector(),用来生成一个反方向遍历序列的 Selector。只
有内部类才有这种灵活性。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: