c++ 实现一个object类_Java类是如何默认继承Object的?

作者:walkinger
链接: https:// juejin.im/post/5ca1e8ad e51d454e6a300048
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

前言

学过Java的人都知道,Object是所有类的父类。但是你有没有这样的疑问,我并没有extends Object,它是怎么默认继承Object的呢?
那么今天我们就来看看像Java这种依赖于虚拟机的编程语言是怎样实现默认继承Object的,以及Java编译器JVM到底是如何做的?


继承自Object验证

首先我们来验证一下Object是不是所有类的父类,随便新建一个Java类,如下图:

19651c9d37b48884656ea9dfafa73ce3.png

从上面的代码可以看出,new MyClass()打点之后可以选择调用的方法有很多,我们定义的MyClass类里面只有一个main方法,那这些方法哪来的,显然是Object里声明的,故MyClass类的父类就是Object,因此,在MyClass中可以使用Object类的public或protected资源。


另外,当A类继承MyClass类时,通过打点也可以调到Object内的方法,这是继承的传递,好比Object是MyClass的“父亲”,MyClass是A类的“父亲”,Object是A类的“爷爷”,间接的继承了Object。


因此,Object是超类,是所有类的父类。

推测可能的原因


要了解Java类是如何默认继承Object的?的原因其实并不需要知道JVM的实现细节。只需了解一下对于这种虚拟机程序的基本原理即可。一般对于这种靠虚拟机运行的语言(如Java、C#等)会有两种方法处理默认继承问题。

编译器处理


在编译源代码时,当一个类没有显式标明继承的父类时,编译器会为其指定一个默认的父类(一般为Object),而交给虚拟机处理这个类时,由于这个类已经有一个默认的父类了,因此,VM仍然会按照常规的方法像处理其他类一样来处理这个类。对于这种情况,从编译后的二进制角度来看,所有的类都会有一个父类(后面可以以此依据来验证)。

JVM处理

编译器仍然按照实际代码进行编译,并不会做额外的处理,即如果一个类没有显式地继承于其他类时,编译后的代码仍然没有父类。然后由虚拟机运行二进制代码时,当遇到没有父类的类时,就会自动将这个类看成是Object类的子类(一般这类语言的默认父类都是Object)。

验证结论

从上面两种情况可以看出,第1种情况是在编译器上做的文章,也就是说,当没有父类时,由编译器在编译时自动为其指定一个父类。第2种情况是在虚拟机上做文章,也就是这个默认的父类是由虚拟机来添加的。


那么Java是属于哪一种情况呢?其实这个答案很好得出。只需要随便找一个反编译工具,将.class文件进行反编译即可得知编译器是如何编译的。


就以上面代码为例,如果是第1种情况,就算MyClass没有父类,但由于编译器已经为MyClass自动添加了一个 Object父类,所以,在反编译后得到的源代码中的MyClass类将会继承Object类的。如果不是这种情况,那么就是第2种情况。


那么实际情况是什么样的呢?现在我们就将MyClass.class反编译看看到底如何。

jd-gui反编:

767fb0a315cc4af7ab8ae4e6072d4b0e.png

使用JDK自带的工具(javap)反编译

CMD命令行下执行:javap MyClass>MyClass.txt

91b2dc491139358fbea00c4303711ce9.png

可以看出实际的反编译后的文件中并没有extends Object,使用排除法,因此是第2情况。
这样来推导出的结论是第2种情况,但事实真的如此吗?为什么网上还有说反编译后的是有extends Object字样?

JDK版本问题?

猜想是JDK版本的问题,于是把JDK版本切换到7,使用jd-gui和javap反编译,接果和使用JDK8反编译后的结果一样,也都没有extends Object
继续换版本,昨晚在宿舍准备到Oracle官网下载JDK 6,但是死活下不来,今早到公司后第一件事就是下载,很顺利,安装后把JDK版本切换到JDK 6。
仍然在CMD窗口执行javap MyClass>MyClass.txt,得到的TXT文件内容如下:

221546899bf456a192c188b7b09b8909.png

what?竟然有extends Object,jd-gui反编译后的依然没有。 即,JDK 6之前使用javap反编译后的MyClass类显式的继承Object,JDK 7以后没有;jd-gui反编译后的不管JDK版本如何始终没有。我们以java自带的工具为准。


总结

那么就是说JDK 6之前是编译器处理,JDK 7之后是虚拟机处理。
但是仔细想想我们在编辑器里(IDE)打点时就能列出Object类下的方法,此时还没轮到编译器和jvm,编辑器就已经知道MyClass类的父类是Object类了,这是因为编辑器为我们做了一些智能处理。(记得区分编辑器和编译器)

(之前发过这篇文章现在怎么又发一遍呢?因为我没有在开头写文章的来源^~^被删除了,其实这篇文章是我首发在掘金的。知乎现在对原创的保护力度很大~)


----------------------------续----------------------------

2019年8月9日10:17:54

既然评论说我论证的不够严谨,那今天来更新一下。

这里是一个简单的测试类:

db821070df64bee29df756b46b2b013c.png

我们直接看字节码文件,切换不同版本,javac编译,javap -c查看字节码文件

5c6509fb60eb40945212f3b89cfafe26.png
JDK 6

c977eae3d5011761efb32faaa2f8850e.png
JDK 7

直接看字节码文件,因为有评论说反编译可能会优化阅读,看的不准特别是第三方反编译工具,这位网友说的很好,感谢。

看到这里,我们的结论只能说,JDK6及之前是编译器处理的,JDK6之后不是编译器处理的。如果问,JDK6之后是JVM处理的吗?我只能说,除了编译器和JVM,还有谁动了这个文件?如果没了,那可以说明是JVM处理的,但论据不够严谨,因为你并没有明确的看到在JVM的源码里,具体在哪个地方处理的!如果追求严谨性(较真)的话,那没办法,作者能力有限,还没能力和精力去JVM源码里找到具体是在哪里处理的。如果有大佬知道或找到了,欢迎评论分享哦。同时感谢那位网友的提醒,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值