【问题标题】:Extending Object implicity隐式扩展对象
【发布时间】:2020-03-18 06:51:30
【问题描述】:

每个人都知道 Object 是超类,所有不扩展任何其他类的类都将隐式扩展 Object 类。我想知道这个隐式扩展是如何工作的。

【问题讨论】:

  • “它是如何工作的”是什么意思? Java 编译器只是将每个不使用extends FooBar 的类视为使用extends java.lang.Object。没有什么比这更神奇的了。

标签: java object inheritance extends


【解决方案1】:

我们有一个文件 child.java

class Child
{
    public static void main(String[] args)
    {
        System.out.println(new Child().toString());
    }
}

从上面的代码我们可以看出,其实Child类的父类是Object,所以我们可以在Child中使用Object类的public或者protected的资源,比如toString方法。那么Java编译器和JVM是怎么做的呢?

知道这个原因其实并不需要知道JVM的实现细节。想想这个虚拟机程序的原理。一般来说,对于运行在虚拟机(如Java)上的这类语言,有两种方法可以处理默认继承问题。

  1. 在编译源码阶段,如果遇到一个没有父类的类,编译器会给它分配一个默认的父类(通常是Object),如果虚拟机处理这个类,因为这个类已经有了默认父类,因此 VM 仍将以通常的方式处理每个类。在这种情况下,从编译二进制的角度来看,所有的类都会有一个父类。

  2. 编译器仍使用实际代码进行编译,不进行额外处理。如果一个类没有显式继承自其他类,并且编译后的代码仍然没有父类。那么在虚拟机运行二进制代码时,如果遇到没有父类的类,则自动将该类视为Object类的子类(一般默认父类为Object)。

    李>

从以上两种情况可以看出,第一种情况是在编译器上做的一篇文章,即在没有父类的情况下,编译器在编译时会自动为其分配一个父类。第二种情况是在虚拟机上做文章,即默认父类由虚拟机添加。

那么 Java 的情况是怎样的呢?事实上,我们可以通过使用 javap 得到这个答案。随便找个反编译工具,反编译.class文件看看编译器是怎么编译的。以上面的代码为例。如果是第一种情况,即使 Child 没有父类,因为编译器已经自动给 Child 添加了 Object 父类,反编译后得到的源码中的 Child 类是继承自 Object 类的。如果不是这种情况,那就是第二种情况。

首先,将child.java编译成Child.class

%javac child.java

现在我们用JDK的反编译工具javap来反编译Child.class,首先执行如下命令:

 % javap -c Child

在命令之后,我们的字节码以某种可读的形式出现,我们可以在其中识别我们的方法、整数、命令和字符串

class Child {
  Child();
    Code:
       0: aload_0
       1: invokespecial #1         // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic  #2 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: new     #3 // class Child
       6: dup
       7: invokespecial #4         // Method "<init>":()V
      10: invokevirtual #5         // Method java/lang/Object.toString:()Ljava/lang/String;
      13: invokevirtual #6         // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      16: return
}

从上面这段代码可以看出,Test已经继承自Object,所以可以断定Java是属性的第一种情况,即编译器指定Object为其默认父类没有父类的类。

【讨论】:

  • 比较简单的javap 输出class Foo {}class Foo extends Object {}
  • @Joachim Sauer,对于 JDK6 之前的所有版本,您是对的。使用javap反编译的Child类显式继承Object。但 JDK 7 及更高版本不会显式显示“扩展对象”。也就是说JDK 6是编译器处理,JDK 7是虚拟机处理。
猜你喜欢
  • 2018-07-20
  • 2017-12-30
  • 2021-01-24
  • 2015-10-12
  • 2020-01-19
  • 1970-01-01
  • 1970-01-01
  • 2013-10-07
  • 1970-01-01
相关资源
最近更新 更多