`

Object类是如何成为默认父类的

    博客分类:
  • java
阅读更多

经常有Java初学者会问为什么一个没有父类的Java类会自动从java.lang.Object类继承。如下面是一个普通的Java类:

<!---->public class Test    // 从Object类继承
{
    
public static void main(String[] args)
    {
        System.out.println(
new Test().toString());
    }
}


从上面的代码可以看出,实际上,Test类的父类就是Object,因此,在Test中可以使用Object类的publicprotected资源,如toString方法。那么Java编译器和JVM到底是如何做的呢?

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

1. 在编译源代码时,当遇到没有父类的类时,编译器会将其指定一个默认的父类(一般为Object),而虚拟机在处理到这个类时,由于这个类已经有一个默认的父类了,因此,VM仍然会按着常规的方法来处理每一个类。对于这种情况,从编译后的二进制角度来看,所有的类都会有一个父类。

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

从上面两种情况可以看出,第1种情况是在编译器上做的文章,也就是说,当没有父类时,由编译器在编译时自动为其指定一个父类。第2种情况是在虚拟机上做文章,也就是这个默认的父类是由虚拟机来添加的。那么Java是属性哪一种情况呢?其实这个答案很好得出。只需要随便找一个反编译工具,并.class文件进行反编译即可得知编译器是如何编译的。就以上面代码为例,如果是第1种情况,就算Test没有父类,但由于编译器已经为Test自动添加了一个Object父类,因此,在反编译后得到的源代码中的Test类是从Object类继承的。如果没是这种情况,那么就是第2种情况。

现在我们使用JDK带的反编译工具javap来反编译Test.class,先执行下面的命令:

javap Test > Test.txt

打开Test.txt文件后,会看到如下的代码:

<!---->public class Test extends java.lang.Object{
    
public Test();
    
public static void main(java.lang.String[]);
}

 

再使用下面的命令来得到bytecode代码:

javap -c Test >Test1.txt

打开Test1.txt后,会看到如下的代码:

<!---->public class Test extends java.lang.Object{
public Test();
  Code:
   
0:    aload_0
   
1:    invokespecial    #8//Method java/lang/Object."<init>":()V
   4:    return

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


    从上面两段代码可以看出,Test已经从Object继承了,因此,可以断定Java是属性第1种情况,也就是说由编译器为没有父类的类指定了Object作为其默认父类。如果读者还不确定,可以直接打开Test.class,看看里面有没有Object,图1Test.class的十六进制代码:

大家可以看到,Java编译器已经为Test指定了一个默认的Object类作为其父类。目前大多数基于虚拟器的语言都是采用的第1种方法来处理默认父类的,如下面的C#代码:

<!---->using System;

namespace ConsoleApplication1
{
    class Test
    {
       
static void Main(string[] args)
        {
            Console.WriteLine(
new Test().ToString());
        }
    }
}


 使用ildasm.exe将上面的代码反编译后,得到的MSIL代码如下:


<!---->.class private auto ansi beforefieldinit ConsoleApplication1.Test
       extends [mscorlib]System.Object
{
// end of class ConsoleApplication1.Test


    从上面的代码可以清楚地看到,Test类已经有一个System.Object作为父类了

分享到:
评论

相关推荐

    Python基础类继承重写实现原理解析

    在创建类时,如果省略了父类,则默认父类为object, object是所有类的父类,所有类都继承自object。 b. isinstance()用来检查一个对象是否是一个类的实例 如果这个类是这个对象的父类,也会返回True 所有的对象都...

    Object类,Objects类,Date类,DateFormat类,Calendar类,Math类,system类

    文章目录一.Object类概念:方法:toStringequals总结:二.Objects类概念三.Date类概述...一个类如果没有明确的写出extends 父类,默认的爹就是Object类 方法: toString 如果直接输出对象名,没有重写Object类中的toStr

    Java中子类和父类之间的调用关系

     4、编译器会在每个构造方法的第一行隐式添加父类的默认无参构造器,即添加super()。  新手容易犯的错误: class Employee extends Object {  public Employee(int id) {  } } class Teacher extend

    Object类和toString()方法.pptx

    熟记Java中的父类Object类 认识toString()方法并理解其作用 能在一些类里正确重写toString()方法 理解toString()方法的执行机制;public class MyClass { } ;4;System.out.print(对象); //自动调用toString()方法 ...

    Java练习题(试卷)

    在Java语言中,有一个类是所有类或接口的父类,这个类的名称是 java.lang.Object 。 4.在Java中所实现的二维数组,实际上是由一维数组构成的 数组 。 5.在Java中,字符串是作为 对象 出现的。 6.接口可以看作是仅...

    Java类和对象之间的差

    事实上,词:object是全部class的父类,全部class类都默认继承object。  java中类是对一类“事物”的属性和行为一种抽象。比方人类能够定义为一个Person类: public class Person { public int age;//年龄 ...

    Python中类和对象的属性 & 方法

    类:所有类名要求首字母大写,多个单词使用驼峰式命名,所有类都默认继承Object class 类名[(父类)]: 属性:特征 方法:动作 注: python与其他语言不一样,可以动态的加载对象的属性和方法。 2、类属性 & 对象属性...

    python15 类的继承

    类的继承I 构建方法II 两个函数III 一个约束IV object类V 两个与内存空间有关的python内置功能VI 子类对父类的属性或方法的重定义属性重定义方法重定义VII 类的多继承 I 构建方法 记住类名后面的括号不是类的参数,...

    2.接口与抽象类的介绍他们之间的异同点及接口是项目分层与618大促接口的实现.docx

    Java 中所有类的根父类是 Object 类,它提供了一些基本方法,如 clone()、finalize()、notify()、wait()、getClass()、toString() 等。Java 的继承是可传递的,即如果 A 继承自 B,而 B 继承自 C,那么 A 也继承自 C...

    抽象类和接口的区别

    那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。  包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样, 同样可以拥有成员变量和普通的成员方法。...

    【05-面向对象(下)】

    •对一个final变量来说,不管它是类变量、实例变量,还是局部变量,只要该变量满足3个条件,这个final变量就 不再是一个变量,而是相当于一个直接量。  –使用final修饰符修饰;  –在定义该final变量时指定...

    java基础.txt

    //其实Person也有继承 ,默认继承Object } 特点: java中的类只有单继承,接口具有多继承 继承具有单根性,一个类只能有一个父类 不能继承父类的有三种情况 · 用private修饰的属性和方法 · 构造方法 · ...

    java 程序设计试题及答案(8套合辑)

    1.下列特点中,哪个是Java 虚拟机执行的特点之一? A、字节代码 B、多进程 C、静态连接...17.applet类的直接父类是: A、Component类 B、Container类 C、Frame类 D、Panel类 18.下面关于沙箱模型的叙述中错误的是

    Python自动化测试面试题.docx

    Python3 默认是新式类,不用写,直接可用。 使用 super 可以提高代码的复用性、可维护性。修改代码时,只需修改一处。 代码举例: class baseClass: def test1(self, num): print(num) class sonClass(baseClass): ...

    java经典面试2010集锦100题(不看你后悔)

    A) 在一个类的声明里声明的类,也叫做内部类或嵌套类,内部类可以作为外包类的一个成员使用,可以访问外包类的所有成员,包括私有成员。 B) 内部类的访问权限可以被定义为public、protected、private和default。但是...

    JAVA面试题最全集

    修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被...

    java 面试题 总结

    新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。 3.封装: 封装是把...

    c#学习笔记——学习心得

    类的方法主要是和类相关联的动作,它是类的外部界面,对于那些私有的字段来说,外部界面实现对它们的操作一般只能通过方法来实现。方法在类或结构中声明,声明时需要制定访问级别、返回值、方法名称及方法参数。一个...

    android反编译(dex2jar.zip)

    5. 修复读取dex中java/lang/Object类时其父类是null导致的一个NPE问题 6. 提高异常信息的可读性 Fixes issue 44 反编译步骤 1、把 class.dex 拷贝到 dex2jar.bat 所在目录,直接拖动 class.dex 到 dex2jar.bat,...

Global site tag (gtag.js) - Google Analytics