隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0
          數據加載中……

          java.lang.Object是如何成為默認父類的

          本文為原創,如需轉載,請注明作者和出處,謝謝!

          經常有
          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的十六進制代碼:



                                                          圖1

             大家可以看到,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作為父類了。






          Android開發完全講義(第2版)(本書版權已輸出到臺灣)

          http://product.dangdang.com/product.aspx?product_id=22741502



          Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


          新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

          posted on 2008-05-06 15:14 銀河使者 閱讀(2777) 評論(0)  編輯  收藏 所屬分類: java 原創

          主站蜘蛛池模板: 浏阳市| 库伦旗| 芮城县| 修武县| 峡江县| 巫山县| 台前县| 揭东县| 丹阳市| 邻水| 苍梧县| 梧州市| 高要市| 道孚县| 东兴市| 陆川县| 宁津县| 正蓝旗| 孟连| 社会| 新龙县| 广德县| 巴彦县| 吉木萨尔县| 永福县| 泰州市| 万山特区| 安福县| 武功县| 武冈市| 睢宁县| 昭平县| 牙克石市| 仁怀市| 和平区| 商丘市| 梧州市| 绿春县| 页游| 库尔勒市| 巴彦淖尔市|