摘要 为什么说接口巧妙地实现了类似多继承的机制。使用接口的核心原因是,为了能够向上转型为多个基类型。即利用接口的多实现,可向上转型为多个接口基类型。
使用接口的核心原因是,为了能够向上转型为多个基类型。即利用接口的多实现,可向上转型为多个接口基类型。以前在学Java的时候对于接口是直接飙过去,并未尝试去深究它的意义,只是简单地记住了它是用来折衷地解决多继承问题。直到最近重新开始复习,才被这一问题弄得晕头转向的。
先来看一下为何 Java 不支持多继承,原因是多继承容易导致钻石危机(也称棱形问题),用一幅图来说明一下:
使用接口的核心原因是,为了能够向上转型为多个基类型。即利用接口的多实现,可向上转型为多个接口基类型。以前在学Java的时候对于接口是直接飙过去,并未尝试去深究它的意义,只是简单地记住了它是用来折衷地解决多继承问题。直到最近重新开始复习,才被这一问题弄得晕头转向的。
先来看一下为何 Java 不支持多继承,原因是多继承容易导致钻石危机(也称棱形问题),用一幅图来说明一下:

假设 类A 中有一个public方法 fun(),然后 类B 和 类C 同时继承了 类A,在 类B 或 类C 中各自对方法 fun()进行了覆盖,这时 类D 通过多继承同时继承了 类B 和 类C,这样便导致钻石危机了,程序在运行的时候对于方法 fun()该如何判断?
所以 Java 并不支持多继承,但是 Java 通过接口可以折衷地解决多继承问题,用一段代码来说明一下比较容易理解:
public
interface
HowToEat {
public
abstract
String howToEat();
}
然后编写一个Checken类,暂时把它想象成父类。
public
class
Checken
implements
HowToEat {
@Override
public
String howToEat() {
return
"Chicken: Fry it."
;
}
}
再编写一个Orange类,同样暂时把它想象成父类。
public
class
Orange
implements
HowToEat {
@Override
public
String howToEat() {
return
"Orange: Make it juice."
;
}
}
最后我们通过测试类 MainTest 来理解接口是如何实现类似多继承机制的。
public
class
MainTest {
public
static
void
main(String[] args) {
HowToEat test =
new
Checken();
System.out.println(test.howToEat());
test =
new
Orange();
System.out.println(test.howToEat());
}
}
|
上面代码的运行结果如下:

当我们使用 HowToEat Test = new Checken(); 的时候,接口中的 howToEat() 方法采用 Checken.howToEat() 来实现,当我们使用 test = new Orange() 的时候,接口中的 howToEat() 方法采用 Orange.howToEat() 来实现,这样是不是可以想象成 HowToEat 类同时继承了 Checken 类和 Orange 类,但具体继承哪个特性则在 new 的时候再来进行决定,这样就巧妙地解决钻石危机同时又可以建立类似多继承的机制。

到这里我们可以进行扩展,接口就是标准。最近在学操作系统,书中讲到“操作系统是用户和计算机硬件之间的接口。用户通过操作系统来使用计算机系统,操作系统则为用户屏蔽了硬件细节,因此,应用程序和用户通常不需要关系计算机的硬件细节”。看到这里,我想大概 C++的多继承和 Java 的接口技术就是想要达到这种目的吧。举个最简单的例子,就是手机和U盘等硬件移动设备都有USB接口,电脑端的USB接口和硬件移动设备的USB接口都遵守一定规则,这样不管你的硬件移动设备内部是怎样实现读写操作的都可以实现与电脑的连接,若不遵守规则则会导致电脑端需要安装成千上万个USB接口。这时我们便可以联想 Java 中的 Comparable等接口了。
如果对于接口还是无法理解过来,当然也可以使用内部类(嵌套类)来实现类似多继承,不必担心会发生钻石危机,因为用内部类实现多继承过程中由设计者重新进行函数命名,从而避免了钻石危机。下面用代码来进行说明:
要继承的类 Father。
1
2
3
4
5
|
public
class
Father {
public
void
output() {
System.out.println(
"father"
);
}
}
|
要继承的类 Mother。
1
2
3
4
5
|
public
class
Mother {
public
void
output() {
System.out.println(
"mother"
);
}
}
|
类 Son 同时继承了 Father 和 Mother 的 output() 方法的实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
class
Son {
class
Father_son
extends
Father {
}
class
Mother_son
extends
Mother {
}
public
void
father() {
(
new
Father_son()).output();
}
public
void
mother() {
(
new
Mother_son()).output();
}
}
|
测试类 MainTest。
1
2
3
4
5
6
7
|
public
class
MainTest {
public
static
void
main(String[] args) {
Son test =
new
Son();
test.father();
test.mother();
}
}
|
测试结果图如下:

分享到:
当我们使用 HowToEat Test = new Checken(); 的时候,接口中的 howToEat() 方法采用 Checken.howToEat() 来实现,当我们使用 test = new Orange() 的时候,接口中的 howToEat() 方法采用 Orange.howToEat() 来实现,这样是不是可以想象成 HowToEat 类同时继承了 Checken 类和 Orange 类,但具体继承哪个特性则在 new 的时候再来进行决定,这样就巧妙地解决钻石危机同时又可以建立类似多继承的机制。

到这里我们可以进行扩展,接口就是标准。最近在学操作系统,书中讲到“操作系统是用户和计算机硬件之间的接口。用户通过操作系统来使用计算机系统,操作系统则为用户屏蔽了硬件细节,因此,应用程序和用户通常不需要关系计算机的硬件细节”。看到这里,我想大概 C++的多继承和 Java 的接口技术就是想要达到这种目的吧。举个最简单的例子,就是手机和U盘等硬件移动设备都有USB接口,电脑端的USB接口和硬件移动设备的USB接口都遵守一定规则,这样不管你的硬件移动设备内部是怎样实现读写操作的都可以实现与电脑的连接,若不遵守规则则会导致电脑端需要安装成千上万个USB接口。这时我们便可以联想 Java 中的 Comparable等接口了。
如果对于接口还是无法理解过来,当然也可以使用内部类(嵌套类)来实现类似多继承,不必担心会发生钻石危机,因为用内部类实现多继承过程中由设计者重新进行函数命名,从而避免了钻石危机。下面用代码来进行说明:
要继承的类 Father。
1
2
3
4
5
|
public
class
Father {
public
void
output() {
System.out.println(
"father"
);
}
}
|
要继承的类 Mother。
1
2
3
4
5
|
public
class
Mother {
public
void
output() {
System.out.println(
"mother"
);
}
}
|
类 Son 同时继承了 Father 和 Mother 的 output() 方法的实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public
class
Son {
class
Father_son
extends
Father {
}
class
Mother_son
extends
Mother {
}
public
void
father() {
(
new
Father_son()).output();
}
public
void
mother() {
(
new
Mother_son()).output();
}
}
|
测试类 MainTest。
1
2
3
4
5
6
7
|
public
class
MainTest {
public
static
void
main(String[] args) {
Son test =
new
Son();
test.father();
test.mother();
}
}
|
测试结果图如下:

分享到:
原文:
http://my.oschina.net/keyven/blog/206180