用AI赚第一桶💰低成本搭建一套AI赚钱工具,源码可二开。 广告
## [为什么需要内部类](https://lingcoder.gitee.io/onjava8/#/book/11-Inner-Classes?id=%e4%b8%ba%e4%bb%80%e4%b9%88%e9%9c%80%e8%a6%81%e5%86%85%e9%83%a8%e7%b1%bb) 至此,我们已经看到了许多描述内部类的语法和语义,但是这并不能同答“为什么需要内部类”这个问题。那么,Java 设计者们为什么会如此费心地增加这项基本的语言特性呢? 一般说来,内部类继承自某个类或实现某个接口,内部类的代码操作创建它的外部类的对象。所以可以认为内部类提供了某种进入其外部类的窗口。 内部类必须要回答的一个问题是:如果只是需要一个对接口的引用,为什么不通过外部类实现那个接口呢?答案是:“如果这能满足需求,那么就应该这样做。”那么内部类实现一个接口与外部类实现这个接口有什么区别呢?答案是:后者不是总能享用到接口带来的方便,有时需要用到接口的实现。所以,使用内部类最吸引人的原因是: > 每个内部类都能独立地继承自一个(接口的)实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。 如果没有内部类提供的、可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。也就是说,内部类允许继承多个非接口类型(译注:类或抽象类)。 为了看到更多的细节,让我们考虑这样一种情形:即必须在一个类中以某种方式实现两个接口。由于接口的灵活性,你有两种选择;使用单一类,或者使用内部类: ~~~ // innerclasses/mui/MultiInterfaces.java // Two ways a class can implement multiple interfaces // {java innerclasses.mui.MultiInterfaces} package innerclasses.mui; 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 // For concrete or abstract classes, inner classes // produce "multiple implementation inheritance" // {java innerclasses.MultiImplementation} 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()); } } ~~~ 如果不需要解决“多重继承”的问题,那么自然可以用别的方式编码,而不需要使用内部类。但如果使用内部类,还可以获得其他一些特性: 1. 内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外部类对象的信息相互独立。 2. 在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类。 稍后就会展示一个这样的例子。 3. 创建内部类对象的时刻并不依赖于外部类对象的创建 4. 内部类并没有令人迷惑的"is-a”关系,它就是一个独立的实体。 举个例子,如果**Sequence.java**不使用内部类,就必须声明"**Sequence**是一个**Selector**",对于某个特定的**Sequence**只能有一个**Selector**,然而使用内部类很容易就能拥有另一个方法`reverseSelector()`,用它来生成一个反方向遍历序列的**Selector**,只有内部类才有这种灵活性。