以前阅读《Thinking in Java》的时候,总是感觉到内部类这个东西需要的理由很牵强,甚至觉得这个东西放在JAVA中纯粹是增加了编程人员的阅读压力。在做了许多基于COM的编程工作后,对OOP已经有了一点心得,再次来看这个内部类,就感觉非常有趣和有必要。
我们知道,在Java中,有抽象类和接口两个东西存在,从表面上看,接口interface上一个更纯粹的抽象类。但实际上,它们的重要区别在于,一个类只能“继承”一个抽象类,但它却可以“实现”多个接口。抽象类和接口固然都可以看作是“属性与方法的组织形式”,但接口却不仅仅是更抽象的“抽象类”这么简单。在JAVA中,抽象类是个规规矩矩的类,但接口,却不是一种特殊的类的形式,它的出现,是为了实现java中“多重继承”机制。
举一个例子,电子琴类有方法Tune()、Display()如果从乐器类派生出来,我们可以向上转型,将电子琴类看作是乐器类;但电子琴类的方法也有电器类定义的TurnOn()、TurnOff(),这个时候,我们再也没有办法把电子琴看作是一个电器类的。因为java是单根继承的。这就是一个问题,如何优雅地实现多重继承。
Java是宣称自己实现的是单根继承机制,但多个父类的继承,未必是一件坏事,有的时候它是一个必须的和更优雅的机制。在OOP编程中,如果许多功能是分堆聚集的,那么将它们用不同的接口来组织比用单独一个接口组织起来显得更优雅。因此,接口interface允许多重继承,也就成为一个必须的功能。接口正是为了实现这个功能而诞生的。但是,由于它实现任务的形式看起来和抽象类如此相似,使得初学者可能误认为,接口只是更抽象的抽象类而已。
但多重继承,有一个问题,即如果两个接口定义了同样的方法,如何在实现这两个接口的类中进行区分?如下面的例子:
public interface ICTest {
void ToShout(String v);
}
public interface IBTest {
void ToShout(String v);
}
public class JTest implements ICTest, IBTest {
public void ToShout(String v) {
// TODO Auto-generated method stub}
}
在JTest中的ToShout方法,就没有办法知道它到底来自哪个接口,如何解决这个问题?这里我们使用到了内部类:
//CATest必须实现IBTest接口和ICTest接口
public class CATest {
private class CTest implements ICTest{
public void ToShout(String v) {
// 内部类CTest类实现ICTest
System.out.println(v);
}
}
private class CBTest implements IBTest{
public void ToShout(String v) {
// 内部类CBTest实现IBTest
System.out.println(v);
}
}
//外部类访问两个内部类的方法
public ICTest DelC(){
return new CTest();
}
public IBTest DelB(){
return new CBTest();
}
public void ToShout(){
System.out.println("super");
}
public static void main(String[] args)
{
CATest a=new CATest();
a.ToShout();
//访问两个内部类的方法,是通过CATest的函数,而非使用new的关键字,而且也不能使用new关键字
a.DelC().ToShout("cc");
a.DelB().ToShout("bb");
}
}