子类继承父类,父类实现接口,子类中调用父类和接口的同名成员变量会出现歧义

子类是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会导致歧义,就说得通了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值