子类继承父类,父类实现接口,子类中调用父类和接口的同名成员变量会出现歧义
子类是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会导致歧义,就说得通了。
子类继承父类,父类实现接口,子类中调用父类和接口的同名成员变量会出现歧义相关推荐
- android微信条码支付接口,Android中调用微信支付接口
在我的项目中还没有接入这个功能的时候就听说微信支付的接口很坑爹,用完之后发现别人说的一点也没有错,蛋疼归蛋疼,该用还是要用.在这里把遇到的问题记录一下以免以后需要再次接入的话碰到问题浪费时间. 微信支 ...
- java如何调c 的接口_JAVA中调用C语言接口
写一个Java类,在这个类中包含了需要调用的本地方法的描述. //WinMsgBox.java package edu.netcom.jni; public class WinMsgBox { st ...
- 继承实现的原理、子类中调用父类的方法、封装
一.继承实现的原来 1.继承顺序 Python的类可以继承多个类.继承多个类的时候,其属性的寻找的方法有两种,分别是深度优先和广度优先. 如下的结构,新式类和经典类的属性查找顺序都一致.顺序为D--- ...
- Day19:继承实现的原理、子类中调用父类的方法、封装
一.继承实现的原来 1.继承顺序 Python的类可以继承多个类.继承多个类的时候,其属性的寻找的方法有两种,分别是深度优先和广度优先. 如下的结构,新式类和经典类的属性查找顺序都一致.顺序为D--- ...
- Python 在子类中调用父类方法详解(单继承、多层继承、多重继承)
Python 在子类中调用父类方法详解(单继承.多层继承.多重继承) by:授客 QQ:1033553122 测试环境: win7 64位 Python版本:Python 3.3.5 代码实践 ...
- 在子类中调用父类的方法super
1.没有super之前,在子类里面需要父类里面的逻辑,但是我们是通过派生(自己定义了一个init,增加了一条line) class vehichle:#定义一个交通工具的类Country=" ...
- Python在子类中调用父类方法
1.在子类中调用父类方法 super().方法名() 类名.方法名(self) spuer(要从哪一个类的上一级类开始查找, self).方法名() 子类调用父类方法时,一般都是想对父类方法进行扩展 ...
- qt 子类调用父类的函数_子类中调用父类的方法
父类名 . __init__(self, ...) 可以将父类中的init中的属性重复调用,减少代码的重复 class Vehicle: def __init__(self, name, speed, ...
- python方法调用名字不一样_python中调用父类同名方法
知识回顾: 上节我们学习了类的构造方法. Python中构建构造方法主要使用__init__魔法方法. 实际项目操作中,由于类的继承导致可能覆盖同名的构造方法,导致只能使用子类的构造,而无法调用父类的 ...
最新文章
- 读书笔记:php_tizag_tutorial
- php请求aspx,PHP用curl函数POST请求到ASP页面提示无效请求
- 大势所趋,应用如何适配Android P HEIF图片格式
- tomcat的安装和部署项目
- android ContentObserver监听系统短信和备份短信到本地
- javascript --- 让函数的实例可以链式调用
- 万字干货:一步步教你如何在容器上构建持续部署!
- 链接属性rel=’external’、rel=’nofollow’、rel=’external nofollow’三种写法的区别...
- java 并发_Java并发编程中断机制 so easy
- php中until的用法,JavaScript_jQuery中nextUntil()方法用法实例,本文实例讲述了jQuery中nextUntil( - phpStudy...
- 自动售货机软件工程课设_饮料自动售货机系统实验.docx
- FRED应用:锥透镜的设计
- 大学有必要考华为认证吗?
- 电脑微信语音通话听不到对方声音或无法播放消息语音
- 货币转换程序(双符号)python代码_Python语言程序设计作业四货币转换
- java批处理查询_java 实现批量查询
- 《精通git》笔记之九(储藏与清理、签署工作、搜索)
- 比较强大的破解软件网站
- JLINK烧写U-boot到NAND Flash中
- Graz技术大学计算机图形与视觉小组PEGASUS项目介绍