接口和抽象类是否继承了Object
我们先看一下Java的帮助文档对于Object的描述:
Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.
Object 类是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
注意:描述是Every class(所有的类)。有这句话可以猜想一下,抽象类是继承了Object。
对于继承,我们知道C++语言支持多继承,Java语言只支持单继承。那么Java语言为什么不支持多继承呢?我们先看一看多继承中最典型的钻石问题(菱型缺陷),如下图(图片来源于https://www.cnblogs.com/sddai/p/6516668.html):

其中A、B、C、D是四个类,B继承A,C也继承A,D又同时继承了B和C。如果B和C都有test方法,看如下代码
D d = new D();
d.test();
第一句中当new D(); 的时候会不会调用两次A的构造函数?
第二句中调用的是B里面的test方法还是C里面的test方法?
为了避免以上的问题,Java采用了折衷的方法,只允许单继承,但可以实现多个接口。所以我们可以以java语言是单继承这个前提,来推导一下接口和抽象类是否继承Object。如下:
对于抽象类而言:一个普通类肯定是继承了Object,如果一个抽象类再继承这个普通类,这个时候抽象类肯定也是继承了Object的。而对于没有继承任何类的抽象类而言,如果它没有继承Object,那么当一个普通类继承这个抽象类的时候,这个普通类也肯定没有继承Object,悖论。所以抽象类肯定是继承了Object。
对于接口而言呢:如果接口继承了Object类。那么当一个类实现多个接口的时候,那不就相当于继承了多遍Object?又变成了多继承?这个问题先放一放。
到目前为止,以上的言论还都处于猜想阶段,现在我们就来深入一点,找一下确凿的“证据”。我们都知道Java源文件会先编译成class文件,然后再被jvm执行。那么如果我们能够知道父类在class文件中是怎么存储的,然后看一下接口编译成的class文件,不就知道接口是否继承Object了吗?以下内容涉及字节码,来源于《深入理解Java虚拟机》第二版的6.3节(核心是6.3.4节)。
Java文件编译而成的class文件是二进制文件,没有任何分隔符,所以无论是顺序还是数量都是被严格规定的。
class文件开始的4个字节是 CAFEBABE,表示这是一个能被虚拟机接受的class文件;紧跟着4个字节表示class文件的版本号;紧接着后面是常量池,前两个字节是常量中的常量数量,后面是常量池的内容;常量池后面的2个字节代表访问标志,比如是否public、接口、注解、枚举等;紧接着2个字节代表类的索引;类索引后面两个字节代表父类索引;父类索引后面是接口索引集合,前两个字节代表集合的大小,后面跟具体的接口索引。如下图所示:

注:
1. 由于常量池中常量的数量是用两个字节存储的,也就是说单个class文件中的常量池中常量的个数不会超过2个字节。
2. “索引” 是指在常量池中的第几项常量(从1开始),占两个字节(和常量池中的常量数量占用空间一样)。比如类索引为5,表示类的全类名在常量池中的第5个常量处。
3. 父类索引只使用了两个字节,这也说明了在class文件中父类最多存在一个(除了Object类的父类索引为0外,其他都有值)。
可见,我们只需找出常量池的结尾,即可找出父类索引,从而确定一个类的父类是谁?jdk中有一个javap的命令(javap -v xxx)。可以查看一个类的常量池,从而查看常量池中最后一个常量的值,然后再根据class文件找出对应的值,即可确定常量池的末尾。
例:TestJ1.java 如下:
public class TestJ1 {
}
使用UltraEdit打开TestJ1.class文件,使用命令行输入命令:“javap -v TestJ1”。如下图所示:

由图中可知常量池最后一个常量为”java/lang/Object” (Constant pool 为常量池),在class文件中对应的位置为0x0069~0X0078。所以访问标志的位置为0x0079~0x007a,值为:0x0021;同理类索引的值为:0x0002;父类索引值为:0x0003;接口索引集合长度为:0x0000(该类没有实现接口)。
类索引为:0x0002,换算成10进制是2,找常量池中为#02(#02 表示常量池中的第二项常量)的值,为 #11,再找#11,为Test1(此处为类的全类名。由于TestJ1类没有包,所以是类名。格式如java/lang/Object)。同理父类为:0x0003 --> #3 --> #12 --> java/lang/Object。所以TestJ1继承Object类。
接下来我们写一个最简单的接口如下:
public interface InterSuper1 {
}
class文件和常量池如下:

由上图可以看出在class文件中InterSuper1接口的父类标识符指向的也是Object类。不止如此,如果一个接口有父接口。那么此接口的父类标识符指向的也是Object类。可以说对于class文件而言所有接口的父类都是Object(同理也可证明Object类也是所有抽象类的父类)。
现在我们再回过头看一看上面遗留的问题:如果接口继承了Object类。那么当一个类实现多个接口的时候,那不就相当于继承了多遍Object?又变成了多继承?首先不会继承多遍Object,因为在class文件而言,只能存储一个父类。这个类还是直接或者间接的继承Object。也是单继承,由于接口不能实例化,所以也不会出现上面的菱形缺陷。
至于网上流传的Java 的标准——“Java Language Specification”中的9.2节,如下(来源于http://www.cnblogs.com/softnovo/articles/4546418.html):

我的理解是:首先这段话没有明确说明接口不继承Object;其次它是出自于java语言规范中,所以它的目的是让人们更加容易使用Java,所以故意省略了这个细节也是有可能的;再者如果接口继承Object,上面的观点也能说得通。
还有一个是如下代码,为什么不输出Object中的方法?这个我也无法解释。
public interface SuperInter {
public void test();
public String getString();
}
public static void main(String[] args) {
Method[] methods = SuperInter.class.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
}
参考资料:
《深入理解Java虚拟机》第二版
https://www.cnblogs.com/sddai/p/6516668.html
http://www.cnblogs.com/softnovo/articles/4546418.html
https://blog.csdn.net/xidiancoder/article/details/78011148
https://blog.csdn.net/tengfeixiaoao/article/details/79586949
接口和抽象类是否继承了Object的更多相关文章
- c#中接口、抽象类、继承综合小练习
namespace Test { class Program { static void Main(string[] args) { //作业:橡皮rubber鸭子.木wood鸭子.真实的鸭子real ...
- 接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?
接口可以继承接口,而且支持多重继承.抽象类可以实现(implements)接口,抽象类可继承具体类也可以继承抽象类.
- 接口是否可继承(extends)接口?抽象类是否可实现 (implements)接口?抽象类是否可继承具体类(concrete class)?
接口可以继承接口,而且支持多重继承.抽象类可以实现(implements)接口,抽象类可继承具体类也可以继承抽象类.
- [Think In Java]基础拾遗1 - 对象初始化、垃圾回收器、继承、组合、代理、接口、抽象类
目录 第一章 对象导论第二章 一切都是对象第三章 操作符第四章 控制执行流程第五章 初始化与清理第六章 访问权限控制第七章 复用类第九章 接口 第一章 对象导论 1. 对象的数据位于何处? 有两种方式 ...
- Python开发基础-Day18继承派生、组合、接口和抽象类
类的继承与派生 经典类和新式类 在python3中,所有类默认继承object,但凡是继承了object类的子类,以及该子类的子类,都称为新式类(在python3中所有的类都是新式类) 没有继承obj ...
- python面向对象编程 继承 组合 接口和抽象类
1.类是用来描述某一类的事物,类的对象就是这一类事物中的一个个体.是事物就要有属性,属性分为 1:数据属性:就是变量 2:函数属性:就是函数,在面向对象里通常称为方法 注意:类和对象均用点来访问自己的 ...
- python开发面向对象基础:接口类&抽象类&多态&钻石继承
一,接口类 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实 ...
- Py修行路 python基础 (十五)面向对象编程 继承 组合 接口和抽象类
一.前提回忆: 1.类是用来描述某一类的事物,类的对象就是这一类事物中的一个个体.是事物就要有属性,属性分为 1:数据属性:就是变量 2:函数属性:就是函数,在面向对象里通常称为方法 注意:类和对象均 ...
- python基础之继承派生、组合、接口和抽象类
类的继承与派生 经典类和新式类 在python3中,所有类默认继承object,但凡是继承了object类的子类,以及该子类的子类,都称为新式类(在python3中所有的类都是新式类) 没有继承obj ...
随机推荐
- Android客户端后台发送邮件(JMail)
今天在做项目的时候要处理用户注册问题,里面有个邮箱验证,网上找了一下果然有人做过,但是我拿过来都运行不起来,或者是发送不了邮件.后来我对这个浅浅的研究了一下,贴出来和大家共享. Activity pa ...
- element-ui 的 日历 datetimerange 日期格适化 , 适合1版本
这家伙把我坑坏了 , 本来吧数据准备好了 , 一掉接口居然不好使 ,日期总是有偏差 , 结果一看是提交的数据有问题 , 后台直接接受的字符串 new 的Date , 2017-12-24T16:00: ...
- UVa 11400 Lighting System Design(DP 照明设计)
意甲冠军 地方照明系统设计 总共需要n不同类型的灯泡 然后进入 每个灯电压v 相应电压电源的价格k 每一个灯泡的价格c 须要这样的灯泡的数量l 电压低的灯泡能够用电压高的灯泡替换 ...
- WPF 呼吸灯特效
原文:WPF 呼吸灯特效 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u014117094/article/details/46738621 pa ...
- RPC的发展历史(本质就是双方定义好协议,传递参数后远程调用)
服务器通讯原理就是一台socket服务器A,另一台socket客户端B,现在如果要通讯的话直接以流方式写入或读出. 这样能实现通讯,但有个问题.如何知道更多信息?比如需要发送流大小,编码,Ip等. 这 ...
- TypeScript Array Remove
定义一个数组 tags:any[]; 方法1:filter 删除并不留空位 this.tags = this.tags.filter(tag => tag !== removedTag); 方法 ...
- [Android] 环境优化配置Android Studio发展NDK
======================================================== 作者:qiujuer 博客:blog.csdn.net/qiujuer 站点:www. ...
- XF内容视图和框架
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http:/ ...
- WPF中的PathAnimation(路径动画)
原文:WPF中的PathAnimation(路径动画) WPF中的PathAnimation(路径动画) ...
- Cordova页面加载外网图片失败,Refused to load the image
原文:Cordova页面加载外网图片失败,Refused to load the image 1.使用Cordova页面加载外网图片失败,抛出异常 Refused to load the image ...