假如这个世界上只剩下你一个人,当你正坐在屋子里的时候,这时突然响起了敲门声...

没有父类的Java Class是如何从Object继承的

上一篇 / 下一篇  2008-05-06 15:54:02

查看( 124 ) / 评论( 0 )
本文为原创,如需转载,请注明作者和出处,谢谢!ITPUB个人空间#^ W*G0U4x8`pY d}
ITPUB个人空间d sl|nq&O:c
经常有Java初学者会问为什么一个没有父类的Java类会自动从java.lang.Object类继承。如下面是一个普通的Java类:
Tk2u8`#o0
6[`3EWtAi f2g0public class Test    // 从Object类继承ITPUB个人空间yw~4PE"Tz n
{ITPUB个人空间\:UBH{
        public static void main(String[] args)ITPUB个人空间 CGt"y%i'xG
        {ITPUB个人空间0CU(o+L;aK!y8p
                System.out.println(new Test().toString());
:o:C&I7]I9[V0        }ITPUB个人空间EbG/v,n
}ITPUB个人空间'zH;{ u.jw4V[
ITPUB个人空间:H R F vD#L
从上面的代码可以看出,实际上,Test类的父类就是Object,因此,在Test中可以使用Object类的public或protected资源,如toString方法。那么JVM到底是如何做的呢?ITPUB个人空间+m x| t3_%CC_R6{'l
了解这个原因其实并不需要知道JVM的实现细节。只要思考一下对于这种虚拟机程序的原理即可。一般对于这种靠虚拟机运行的语言(如Java、C#等)会有两种方法处理默认继承问题。ITPUB个人空间~$Xl\8l)C&Uhp
1.  在编译源代码时,当遇到没有父类的类时,编译器会将其指定一个默认的父类(一般为Object),而虚拟机在处理到这个类时,由于这个类已经有一个默认的父类了,因此,VM仍然会按着常规的方法来处理每一个类。对于这种情况,从编译后的二进制角度来看,所有的类都会有一个父类。ITPUB个人空间(d3N u)t]
2.  编译器仍然按着实际代码进行编译,并不会做额外的处理。如果一个类没有显式地继承于其他的类,编译后的代码仍然没有父类。然后由虚拟机运行二进制代码时,当遇到没有父类的类时,就会自动将这个类看成是Object类的子类(一般这类语言的默认父类都是Object)。
0a1tR6T!zd3Yv0ITPUB个人空间:Wq$L.P;yU
从上面两种情况可以看出,第1种情况是在编译器上做的文章,也就是说,当没有父类时,由编译器在编译时自动为其指定一个父类。第2种情况是在虚拟机上做文章,也就是这个默认的父类是由虚拟机来添加的。那么Java是属性哪一种情况呢?其实这个答案很好得出。只需要随便找一个反编译工具,并.class文件进行反编译即可得知编译器是如何编译的。就以上面代码为例,如果是第1种情况,就算Test没有父类,但由于编译器已经为Test自动添加了一个Object父类,因此,在反编译后得到的源代码中的Test类是从Object类继承的。如果没是这种情况,那么就是第2种情况。ITPUB个人空间M/z-KwpN
现在我们使用JDK带的反编译工具javap来反编译Test.class,先执行下面的命名:ITPUB个人空间)B.]d@%N
ITPUB个人空间mD&Ooh.b;?
javap Test > Test.txt
{c$h"?@$]Dk0
y%H7^naW0打开Test.txt文件后,会看到如下的代码:ITPUB个人空间 }J+U&_B2|Bg
ITPUB个人空间_*`mRz3Lt
public class Test extends java.lang.Object{
:Bs rsm"N8M'`W0    public Test();ITPUB个人空间[2C~0wK*IO
    public static void main(java.lang.String[]);ITPUB个人空间5M0gb h@
}
0UW;?/PJ%|5dX0
D6R MD8?s)B`P!g0再使用下面的命名来得到bytecode代码:ITPUB个人空间Ot#TR%c8fk

(v$q|-h!J B)X0javap –c Test >Test1.txtITPUB个人空间|tsuW
ITPUB个人空间!_ q3r}{Y
打开Test1.txt后,会看到如下的代码:ITPUB个人空间XY&xc#N Q"~k
ITPUB个人空间;d(_-k6~~wYX
public class Test extends java.lang.Object{
L V%dHr0public Test();ITPUB个人空间1^LKE]vy3lLo0z
  Code:
V*UW bK/_0   0:        aload_0ITPUB个人空间)N*m7k8|CjWz
   1:        invokespecial        #8; //Method java/lang/Object."<init>":()VITPUB个人空间:iE:E-p:O+l|[
   4:        returnITPUB个人空间5JN,S'zW

5n7c-S#H-w t0public static void main(java.lang.String[]);ITPUB个人空间5kL7FQ\-t
  Code:ITPUB个人空间1YQ G:CY"R!?a
   0:        getstatic        #16; //Field java/lang/System.out:Ljava/io/PrintStream;
BR ?+|(O0   3:        new        #1; //class TestITPUB个人空间 M3gG.[ R.R
   6:        dup
@FA^,cg.KQ"Wh0   7:        invokespecial        #22; //Method "<init>":()VITPUB个人空间0S7M)ah$z{hs
   10:        invokevirtual        #23; //Method java/lang/Object.toString:()Ljava/lang/String;ITPUB个人空间 _#e?J$E:jm$C1C"U
   13:        invokevirtual        #27; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
V2Cz8{&m-XN h0   16:        returnITPUB个人空间0pmUzJp*q
}ITPUB个人空间 a lV,U3Ag s*t

W`}5O$Y}z0从上面两段代码可以看出,Test已经从Object继承了,因此,可以断定Java是属性第1种情况,也就是说由编译器为没有父类的类指定了Object作为其默认父类。如果读者还不确定,可以直接打开Test.class,看看里面有没有Object,图1是Test.class的十六进制代码:ITPUB个人空间Qm%^ ^#m%M:tY N/?
ITPUB个人空间ph#s ^?E

^!S4S|/f!^ ] Ie0javaclass01.jpg

#Sr0jU4nK8B0ITPUB个人空间*l.C.Bp7f6mbX^o2]
图1
F FDYI$s3g\0
W;VB]Ex0大家可以看到,Java编译器已经为Test指定了一个默认的Object类作为其父类。目前大多数基于虚拟器的语言都是采用的第1种方法来处理默认父类的,如下面的C#代码:
u FH X&q(wq0ITPUB个人空间.|#}c(\0X M ?F4`
using System;ITPUB个人空间M rD#oMU&L$r
ITPUB个人空间2} qW!I Lv s
namespace ConsoleApplication1ITPUB个人空间+s6u(Au!U4P5jE
{ITPUB个人空间4b5]`'C&uPd4Y
class TestITPUB个人空间pEG#y3Z2i&U
{ITPUB个人空间qGS m!k
    static void Main(string[] args)ITPUB个人空间 F4@(h Fqex+o
    {ITPUB个人空间%P5ss4{+L(s J8F
        Console.WriteLine(new Test().ToString());ITPUB个人空间o@5n g Qi j+\-W
    }
i\`` cn{3Xz0}ITPUB个人空间W p9M k XzF
}ITPUB个人空间&}*R-JdkW
ITPUB个人空间E7}|q1K
    使用ildasm.exe将上面的代码反编译后,产生的MSIL代码如下:
t;LBH,e6Xr0@0ITPUB个人空间ZE K PZMO
.class private auto ansi beforefieldinit ConsoleApplication1.Test
],_:k`%Av\Z0       extends [mscorlib]System.ObjectITPUB个人空间p _5ig%sD*c
{ITPUB个人空间{8rl4~#l;I;|;I1u9Hc
} // end of class ConsoleApplication1.TestITPUB个人空间bE/B1a)\

~ \ya.f,hd)D0ITPUB个人空间6C%FYn2Tt
    从上面的代码可以下巴清楚地看到,Test类已经有一个System.Object作为父类了。
2oN Y)y-j F.r0
!h#v.Z P[-~l2H+bT0[本帖最后由 银河使者 于 2008-5-6 15:55 编辑]

TAG:

我来说两句

(可选)

日历

« 2008-05-17  
    123
45678910
11121314151617
18192021222324
25262728293031

数据统计

  • 访问量: 3859
  • 日志数: 83
  • 建立时间: 2008-02-08
  • 更新时间: 2008-04-25

RSS订阅

Open Toolbar