经常有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类的public或protected资源,如toString方法。那么Java编译器和JVM到底是如何做的呢?
了解这个原因其实并不需要知道JVM的实现细节。只要思考一下对于这种虚拟机程序的原理即可。一般对于这种靠虚拟机运行的语言(如Java、C#等)会有两种方法处理默认继承问题。
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,图1是Test.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作为父类了
分享到:
相关推荐
在Java编程语言中,`Object`类是所有类的根,每个自定义类如果没有明确指定父类,都默认继承自`Object`。因此,对`Object`类的理解是每个Java开发者的基本功。本文将深入探讨`Object`类,以及其核心方法`equals()`与...
Object类是所有Java类的根父类,无论何时我们创建一个新的类,除非明确指定其他父类,否则它都会默认继承Object类。这使得Object类中的方法对所有Java类都可用,体现了Java的继承性和多态性。 1. **根父类理解** -...
在Java编程语言中,Object类是一个非常基础且重要的类,它是所有类的终极父类。这意味着,无论我们自定义的类是否显式声明了继承,它们实际上都是Object类的间接子类。`Java程序设计:020611_Object类.ppt`这个资料...
Object类在Java中具有举足轻重的地位,它是所有类的直接或间接父类。这意味着每一个自定义类,默认情况下都是Object类的子类,即使没有显式声明也继承了Object类的所有属性和方法。 #### toString() 方法 `...
`getDeclaredFields()` 返回的是类声明的所有字段,不包括继承自父类的字段。如果想获取包括父类在内的所有属性,需要递归遍历父类: ```java void printAllFields(Class<?> clazz) { Field[] fields = clazz....
不论你定义的类是否显式声明父类,都会默认继承Object类。Object类提供了处理对象通用的方法。 - **toString()**:返回对象的字符串表示。默认实现返回类名加@符号后跟对象的内存地址。通常我们需要重写此方法,...
Object 类是 Java 语言中的顶层类,是所有类的直接或间接父类。任何类,如果没有书写 extends 显式继承某个类,都默认直接继承 Object 类,否则为间接继承。Object 类中所定义的方法,是所有对象都具备的方法。 ...
`Object`类是所有类的父类,因此,当我们自定义类时,除非显式声明其他父类,否则默认继承`Object`。多态性是面向对象编程的重要特性,允许我们用父类引用指向子类对象,实现代码的灵活性和可扩展性。例如,可以...
在Python 3.x中,所有类默认都继承自`object`,因此都是新式类。但在Python 2.x中,若未显式指定继承`object`,则不是新式类。为了保证兼容性,建议在Python 2.x中定义类时,即使没有父类,也明确指定继承`object`:...
继承允许创建一个新的类(称为子类或派生类),该类继承了现有类(称为父类或基类)的所有属性和行为。通过继承,子类不仅可以重用父类的功能,还可以扩展或覆盖父类的行为。 #### 二、子类如何调用父类构造方法 ...
Object类是Java语言中所有类的父类,位于java.lang包中。它是所有Java类的终极父类,数组也继承了Object类。然而,接口是不继承Object类的,Object类不作为接口的父类。 Object类提供了几个重要的方法,包括equals...
Java中的`Object`类是所有Java类的根父类,每个自定义的类如果没有明确指定父类,那么它默认就会继承`Object`类。本文将详细介绍`Object`类中的三个重要方法:`toString()`、`equals()`和`hashCode()`。 **1. `...
}}在 ModifierTest2 类中,由于它继承了 ModifierTest1,所以它可以访问所有父类的变量,但 private 变量 privVar 由于私有化,所以无法直接访问,尝试访问会抛出异常。 2. Object 类(了解)Object 类是 Java 中...
- 如果一个类没有显式地指定父类,则默认继承自`Object`类。 - 由于`Object`类的特殊地位,一个`Object`类型的变量可以引用任何对象,包括各种类型的对象和数组等。 **2. `Object`类的方法** `Object`类定义了一...
总的来说,Object类和Class类是Java语言的基础构建块,理解它们的工作原理对于成为一名熟练的Java开发者至关重要。在编程实践中,经常会遇到需要重写`equals()`和`toString()`的情况,以及利用Class对象进行反射操作...
但如果是类实例的成员变量,其析构顺序会是子类的清理逻辑、类成员变量的清理,最后是父类的清理逻辑,因为这些清理动作是伴随着对象被垃圾回收而发生的。 标签"构造函数"强调了这个话题的核心,即构造过程中类实例...
在Java编程语言中,Object类是所有类的父类,它提供了所有对象共有的基本方法。在Java 8中,Object类得到了一些新的特性增强,这些改进使得Java开发者在处理对象时有了更多的灵活性和效率。本文将深入探讨Java 8中...
针对你的需求,我们讨论一个自定义的工具类,它支持处理具有public属性以及父类属性的JSON对象,并利用反射机制进行操作。这个工具类名为`JsonUtil`,以下是关于这个工具类及其涉及知识点的详细说明: 1. **public...
Object Pascal是一种基于Pascal编程语言的面向对象的扩展版本,它在传统的Pascal基础上引入了类、对象、接口等概念,极大地增强了其灵活性和可扩展性。本篇将深入探讨Object Pascal语言的核心特性、语法结构以及在...