组合接口时名字冲突问题
之前从没注意到实现多个接口可能会存在方法冲突的问题,在《Thinking in Java》中看到一个有趣的例子,其本质是重载和重写的问题,关于重载和重写的概念和区别可参看另一篇文章Java基础一:面向对象的特征。首先看例子:
1 interface I1 { 2 void f(); 3 } 4 5 interface I2 { 6 int f(int i); 7 } 8 9 interface I3 { 10 int f(); 11 } 12 13 class C { 14 public int f(){ 15 return 1; 16 } 17 } 18 19 class C2 implements I1,I2{//重载 20 @Override 21 public void f() {} 22 23 @Override 24 public int f(int i) { 25 return 0; 26 } 27 } 28 29 class C3 extends C implements I2{ 30 @Override 31 public int f(int i) {//重载 32 return 0; 33 } 34 } 35 36 class C4 extends C implements I3{ 37 @Override 38 public int f() { //重写 39 return 0; 40 } 41 } 42 43 // class C5 extends C implements I1{} 44 // 45 // interface I4 extends I1,I3{} 46 47 public static void main(String[] args){ 48 MethodCollision methodCollision = new MethodCollision(); 49 C4 c4 = methodCollision.new C4(); 50 System.out.println(c4.f());//输出0 51 }
其中接口I1中存在方法void f(),I2中存在int f(int i),I3中存在int f(),类C中存在int f()的方法。
C2类实现接口I1和I2,其中实现的方法void f()和int f(int i)具有不同的签名,属于重载;
C3类实现接口I2、继承C,C3实现I2中的int f(int i),并继承C中的int f()方法,它们具有不同的签名,属于重载;
C4类实现接口I3、继承C,C4实现I3中的int f(),并继承C中的int f()方法,它们具有相同的签名,并且返回值类型也相同,属于重写(从程序输出0可以说明);
C5类实现接口I1、继承C,理论上,C5类会分别实现和继承I1方法void f()和C方法int f(),它们具有相同的签名,不同的返回值类型,既不是重写,也不能重载,故编译器提示错误;
I4接口继承I1和I3,同样理论上继承void f()和int f(),但既不是重写,也无法重载,编译器报错。
另一个有趣问题是,我如果将接口I1中的void f()改为int f(),会产生什么效果呢?
1 interface I1 { 2 int f(); 3 } 4 5 interface I2 { 6 int f(int i); 7 } 8 9 interface I3 { 10 int f(); 11 } 12 13 class C { 14 public int f(){ 15 return 1; 16 } 17 } 18 19 class C2 implements I1,I2{//重载 20 @Override 21 public int f() { 22 return 0; 23 } 24 25 @Override 26 public int f(int i) { 27 return 0; 28 } 29 } 30 31 class C3 extends C implements I2{ 32 @Override 33 public int f(int i) {//重载 34 return 0; 35 } 36 } 37 38 class C4 extends C implements I3{ 39 @Override 40 public int f() { //重写 41 return 0; 42 } 43 } 44 45 class C5 extends C implements I1{}//不重写该函数,继承自C的方法即为实现 46 47 interface I4 extends I1,I3{} 48 49 class C6 implements I4{//I1和I3的方法一样,实现类只实现一个 50 @Override 51 public int f() { 52 return 0; 53 } 54 } 55 56 public static void main(String[] args){ 57 MethodCollision methodCollision = new MethodCollision(); 58 C4 c4 = methodCollision.new C4(); 59 System.out.println(c4.f());//0 60 61 C5 c5 = methodCollision.new C5(); 62 System.out.println(c5.f());//1 63 }
其中接口I1中存在方法int f(),I2中存在int f(int i),I3中存在int f(),类C中存在int f()的方法。
C2类实现接口I1和I2,其中实现的方法int f()和int f(int i)具有不同的签名,属于重载;
C3类实现接口I2、继承C,属于重载;
C4类实现接口I3、继承C,属于重写(从程序输出0可以说明);
C5类实现接口I1、继承C,C5类会分别实现和继承I1方法int f()和C方法int f(),其与C4类是相同的,它是重写吗?不是,因为其继承自C的函数已经实现了该接口,没有重写(从程序输出1可以说明);
I4接口继承I1和I3,同时继承I1和I3的int f(),它们具有相同的方法签名和返回值类型,所以I4具有一个int f()(可通过C6实现类看出);
C6类实现接口I4,具有一个实现函数int f()。
总结:
- 类不可以多重继承,接口可以多重继承;
- 组合接口时,可能会存在方法重载和重写的问题,并且可能会引入代码的混乱,降低代码可读性,故尽量避免这种情况;
- 通过该例,可以学习继承、接口实现、重载和重写概念,其中一点是类继承的方法也可以作为实现接口的实现方法。