本文为原创,如需转载,请注明作者和出处,谢谢!
经常有Java初学者会问为什么一个没有父类的Java类会自动从java.lang.Object类继承。如下面是一个普通的Java类:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->publicclassTest//从Object类继承
{
publicstaticvoidmain(String[]args)
{
System.out.println(newTest().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文件后,会看到如下的代码:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->publicclassTestextendsjava.lang.Object{
publicTest();
publicstaticvoidmain(java.lang.String[]);
}
再使用下面的命令来得到bytecode代码:
javap -c Test
>Test1.txt
打开Test1.txt后,会看到如下的代码:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->publicclassTestextendsjava.lang.Object{
publicTest();
Code:
0:aload_0
1:invokespecial#8;//Methodjava/lang/Object."<init>":()V
4:return
publicstaticvoidmain(java.lang.String[]);
Code:
0:getstatic#16;//Fieldjava/lang/System.out:Ljava/io/PrintStream;
3:new#1;//classTest
6:dup
7:invokespecial#22;//Method"<init>":()V
10:invokevirtual#23;//Methodjava/lang/Object.toString:()Ljava/lang/String;
13:invokevirtual#27;//Methodjava/io/PrintStream.println:(Ljava/lang/String;)V
16:return
}
从上面两段代码可以看出,Test已经从Object继承了,因此,可以断定Java是属性第1种情况,也就是说由编译器为没有父类的类指定了Object作为其默认父类。如果读者还不确定,可以直接打开Test.class,看看里面有没有Object,图1是Test.class的十六进制代码:
图1
大家可以看到,Java编译器已经为Test指定了一个默认的Object类作为其父类。目前大多数基于虚拟器的语言都是采用的第1种方法来处理默认父类的,如下面的C#代码:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->usingSystem;
namespaceConsoleApplication1
{
classTest
{
staticvoidMain(string[]args)
{
Console.WriteLine(newTest().ToString());
}
}
}
使用ildasm.exe将上面的代码反编译后,得到的MSIL代码如下:
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->.classprivateautoansibeforefieldinitConsoleApplication1.Test
extends[mscorlib]System.Object
{
}//endofclassConsoleApplication1.Test
从上面的代码可以清楚地看到,Test类已经有一个System.Object作为父类了。
国内最棒的Google Android技术社区(eoeandroid),欢迎访问!《银河系列原创教程》发布《Java Web开发速学宝典》出版,欢迎定购
分享到:
相关推荐
Java中的Object类是所有类的父类,任何类都默认继承Object。Object类提供了多种方法,以下是其中一些重要的方法: 1. clone方法:保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出...
`java.lang` 包含了所有 Java 程序都默认导入的基本类,如 `Object`、`String` 和 `System`。`java.util` 提供了集合框架、日期时间、随机数生成等工具类。`java.io` 包则涉及输入输出操作,如文件读写、流处理等。 ...
这意味着即使是用户自定义的类,如果没有明确指定父类,也会默认继承自`Object`类。 **3. 基本数据类型的封装类** Java提供了对基本数据类型的封装类,这些类位于`java.lang`包中。对于每个基本数据类型都有一个...
`java.lang` 包含了所有Java程序都默认导入的基本类,如`Object`, `String`, `System`等。`java.util` 提供了各种实用工具类,如集合框架、日期时间处理、随机数生成等。`java.io` 和 `java.nio` 用于输入输出操作,...
6. `java.lang.Object`的重要性:`java.lang.Object`是Java所有类的根类,任何自定义类如果没有指定父类,那么默认继承自`Object`。 7. Swing事件处理机制:Swing的事件处理机制基于监听器模式,包括事件的监听者...
- `java.io.FileReader` → `java.io.Reader` → `java.lang.Object` - `java.io.FileWriter` → `java.io.Writer` → `java.lang.Object` - **构造方法**: - `FileReader(String fileName)`:创建一个`...
在Java编程语言中,`Object`类是所有类的根,每个自定义类如果没有明确指定父类,都默认继承自`Object`。因此,对`Object`类的理解是每个Java开发者的基本功。本文将深入探讨`Object`类,以及其核心方法`equals()`与...
在Java中,`java.lang.Class` 类提供了获取类属性的方法。要获取类的所有属性(包括public、private、protected以及默认访问权限的属性),可以使用以下代码: ```java Class<?> clazz = Class.forName("全限定...
1. **基础类库**:Java API的基础类库包括`java.lang`包,其中包含了所有Java程序都默认导入的基本类,如`String`、`Object`、`System`等。`Object`类是所有类的父类,提供了`equals()`、`hashCode()`和`toString()`...
1. **Class类**:`java.lang.Class`是Java反射的基础,它代表了Java中的每一个类或接口。通过`Class`对象,我们可以获取到类的各种信息,如类名、构造器、方法、字段等。 2. **获取Class对象**: - `Class.forName...
`java.lang.Number` 是一个抽象类,用于表示数值类型的基本封装类的父类。 - **`java.lang.Double`:** 错误。`java.lang.Double` 实际上是一个类,用于包装 `double` 类型的原始数据。 - **`java.lang.Math`:** 错误...
1. **Java基础类库**:Java的基础类库包括`java.lang`包,它是所有Java程序的默认导入包,包含如`String`, `Object`, `System`等核心类。`String`类用于处理文本字符串,`Object`是所有Java类的父类,`System`类提供...
首先,Java SE API的核心在于Java语言的核心类库,包括`java.lang`包,它是每个Java程序的默认导入包,包含了如`String`、`Object`、`System`等基础类。`Object`类是所有类的父类,提供了`equals()`和`hashCode()`等...
面向对象程序设计(Object-Oriented Programming,OOP)是现代软件开发中广泛采用的一种编程范式,尤其在Java语言中得到了深入的应用。本资源"面向对象程序设计Java.ppt"是一个基础讲解材料,旨在帮助初学者理解并...
Java代理机制主要依赖于`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。通过实现`InvocationHandler`接口并利用`Proxy.newProxyInstance()`方法可以创建一个动态代理对象。该对象能够...
1. **基础类库**:Java API的基础类库包括`java.lang`包,它是所有Java程序的默认导入包,包含如`String`、`Integer`、`Object`等核心类。`Object`是所有类的父类,提供了诸如`equals()`、`hashCode()`和`toString()...
所有Java程序默认导入此包,因此无需显式导入`java.lang`中的类。`Object`类是所有类的父类,它提供了诸如`equals()`、`hashCode()`、`toString()`等基本方法。`equals()`方法用于比较两个对象是否相等,通常需要...
1. **基础类库**:Java的基础类库包括了`java.lang`包,它是所有Java程序的默认导入包,包含了诸如`String`、`Integer`、`Object`等基本类型和对象。`String`类用于处理文本字符串,而`Object`类是所有Java类的父类...
作为Java程序的默认导入包,java.lang包含了所有Java程序都需要的基本类。其中的`Object`类是所有Java类的根类,提供了诸如`equals()`、`hashCode()`和`toString()`等通用方法。此外,还有基本类型的包装类,如`Byte...
Object 类是 Java 中的顶级父类,所有的 Java 类都是 Object 类的子类。 4. Object 类常用方法有哪些?Object 类常用方法有 equals、hashCode、toString、wait、notify、clone、getClass 等。 5. Java 中有没有...