子类是C,父类是A,A实现了接口P
当父类A和接口P都定义了一个同名的属性b,那么在子类C调用这个属性是调用的谁的呢?
连着写
interface P{
int b = 10;
}
class A{
int b = 5;
}
class C extends A implements P{
public void print(){
System.out.print(b);//报错,The field b is ambiguous
}
}
这样写编译不通过,错误提示「字段b是有歧义的」。
也就是说,编译器它不知道你是这个b是父类A的还是接口P的
要想访问父类A的属性b的话需要写成 super.a
,而要访问接口P的属性b的话则是这样 P.a
分开写
interface P{
int b = 10;
}
class A implements P{
int b = 5;
}
class C extends A{
public void print(){
System.out.print(b);//输出5
}
}
这样写没问题,也不会报错,最后输出为5,说明调用的是父类A的b
那么为什么同样都是A实现P,C再继承A,C访问属性b,连着写就报错,而分开写就不报错了呢?
目前我这样理解的:分开写时,编译器在字面上是编译C类时,是看不到父类A实现了接口P的,没有显式产生链式关系,而实际上的确是C继承A,A再实现P的。
不过我对于连在一起写会出现b的歧义,有些疑问。只写一个 b
,按照向上查找,很明显是选择调用父类的b
呀,为什么会出现歧义呢。
在这里暂且留有疑问
(晚上我在整理笔记的时候又在上面这个例子中捣鼓了几下,突然发现我好像知道出现歧义的根本原因了,而之前的认识和猜测有些错误,我也不删改了,记录下整个思考过程)
还是C继承A,A实现P,这次是在接口P中定义了一个抽象方法,但是A和C都没有实现它,并且是A和C是分开写的:
interface P {
void af();
}
class A implements P{//编译不通过,The type A must implement the inherited abstract method P.af()
}
class C extends A {
}
这里肯定会报错,因为我们知道类要实现接口就必须实现接口中的抽象方法,它的报错位置在父类A处,报错提示为「A类必须要实现接口P的抽象方法af() 」
然后我们看将A和C写在一块会怎样:
interface P {
void af();
}
class A {
}
class C extends A implements P{//编译不通过,The type C must implement the inherited abstract method P.af()
}
这次当然还是报错,但报错的位置并不是A处了,而是C处! 报错信息为「C类必须实现接口P的抽象方法af() 」。很奇怪吗不是,既然A实现了P,C又继承A,如果P中抽象方法没有实现那就应该像上面分开写的情况一样,报错父类A没有实现,因为是他直接实现的接口,有问题肯定先找他啊,怎么也轮不到子类C来实现吧。
然后我就想,只有一种可能,可以来解释这个诡异的情况。
我猜测这种连着写 C extends A implements P
实际上根本不是A实现P,C又继承A,父类A和接口P根本就没关系!这样写的真正含义是子类C继承了父类A,然后C又实现了接口P。这是两个完全没有关系的分支。
为了证实我的猜测,我这次在接口P中定义了一个属性d,然后在A类中去调用这个接口P的属性d,这样做的理论依据是:如果A与P是有实现关系的,那么A中就可以调用到P的属性d,如果不能调用,则说明A并没有实现P,他们也就没有关系。
interface P {
int d = 10;
}
class A {
public void f() {
System.out.println(d);//这里的b报错了,d cannot be resolved to a variable
}
}
class C extends A implements P{
}
报错了!的确是A处的「d不能解析为一个变量」,A并不能访问到接口P的属性d。而且我还发现在上一个抽象方法的例子中,如果在C类中输入af会自动提示重写实现接口P的af()方法,而在A中并没有提示。这样就实锤了A根本就没有实现接口P,只是C继承了它,然后C自己实现了接口P。
绕了一大圈,最后终于弄清楚了,这两种写法根本就是两回事儿,连着写 C extends A implements P
其实是:两个层次两条支线,而分开写 C extends A; A implements P
才是三个层次一条单线。这是和表面上看着不太对应嚎。
这样再来解释在C中调用父类A和接口P都有的同名属性b会导致歧义,就说得通了。