qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問(wèn) http://qaseven.github.io/

          Java字節(jié)碼深入解析

          一:Java字節(jié)代碼的組織形式

            類(lèi)文件{

            OxCAFEBABE,小版本號(hào),大版本號(hào),常量池大小,常量池?cái)?shù)組,訪問(wèn)控制標(biāo)記,當(dāng)前類(lèi)信息,父類(lèi)信息,實(shí)現(xiàn)的接口個(gè)數(shù),實(shí)現(xiàn)的接口信息數(shù)組,域個(gè)數(shù),域信息數(shù)組,方法個(gè)數(shù),方法信息數(shù)組,屬性個(gè)數(shù),屬性信息數(shù)組

            }

            二:查看方法 --- javap命令

            例子:有一個(gè)Java類(lèi)Demo.java

        1. public class Demo { 
        2.     private String str1; 
        3.     private String str2; 
        4.     private int num1; 
        5.     private int num2; 
        6.     public static final String STATIC_DATA = "hello world"
        7.      
        8.     private void sayHello1(){ 
        9.         System.out.println("this is method1..."); 
        10.     } 
        11.     private void sayHello2(){ 
        12.         System.out.println("this is method2..."); 
        13.     } 
        14.     public void sayHello3(){ 
        15.         System.out.println("this is method3..."); 
        16.     } 
        17. }
        18.   通過(guò)jdk自帶的反編譯工具命令 javap 可以查看class文件的字節(jié)碼信息

          D:\>javap -verbose Demo >> Demo.txt

            Demo.txt:

        19. Compiled from "Demo.java" 
        20. public class Demo extends java.lang.Object 
        21.   SourceFile: "Demo.java" 
        22.   minor version: 0 
        23.   major version: 49   
        24.   
        25.   Constant pool: 
        26. const #1 = class      #2;   //  Demo 
        27. const #2 = Asciz     Demo; 
        28. const #3 = class      #4;   //  java/lang/Object 
        29. const #4 = Asciz     java/lang/Object; 
        30. const #5 = Asciz     str1; 
        31. const #6 = Asciz     Ljava/lang/String;; 
        32. const #7 = Asciz     str2; 
        33. const #8 = Asciz     num1; 
        34. const #9 = Asciz     I; 
        35. const #10 = Asciz   num2; 
        36. const #11 = Asciz   STATIC_DATA; 
        37. const #12 = Asciz   ConstantValue; 
        38. const #13 = String  #14//  hello world 
        39. const #14 = Asciz   hello world; 
        40. const #15 = Asciz   <init>; 
        41. const #16 = Asciz   ()V; 
        42. const #17 = Asciz   Code; 
        43. const #18 = Method       #3.#19;   //  java/lang/Object."<init>":()V 
        44. const #19 = NameAndType    #15:#16;//  "<init>":()V 
        45. const #20 = Asciz   LineNumberTable; 
        46. const #21 = Asciz   LocalVariableTable; 
        47. const #22 = Asciz   this
        48. const #23 = Asciz   LDemo;; 
        49. const #24 = Asciz   sayHello1; 
        50. const #25 = Field   #26.#28;  //  java/lang/System.out:Ljava/io/PrintStream; 
        51. const #26 = class    #27//  java/lang/System 
        52. const #27 = Asciz   java/lang/System; 
        53. const #28 = NameAndType    #29:#30;//  out:Ljava/io/PrintStream; 
        54. const #29 = Asciz   out; 
        55. const #30 = Asciz   Ljava/io/PrintStream;; 
        56. const #31 = String  #32//  this is method1... 
        57. const #32 = Asciz   this is method1...; 
        58. const #33 = Method       #34.#36;  //  java/io/PrintStream.println:(Ljava/lang/String;)V 
        59. const #34 = class    #35//  java/io/PrintStream 
        60. const #35 = Asciz   java/io/PrintStream; 
        61. const #36 = NameAndType    #37:#38;//  println:(Ljava/lang/String;)V 
        62. const #37 = Asciz   println; 
        63. const #38 = Asciz   (Ljava/lang/String;)V; 
        64. const #39 = Asciz   sayHello2; 
        65. const #40 = String  #41//  this is method2... 
        66. const #41 = Asciz   this is method2...; 
        67. const #42 = Asciz   sayHello3; 
        68. const #43 = String  #44//  this is method3... 
        69. const #44 = Asciz   this is method3...; 
        70. const #45 = Asciz   SourceFile; 
        71. const #46 = Asciz   Demo.java; 
        72.   
        73. public static final java.lang.String STATIC_DATA; 
        74.   Constant value: String hello world 
        75. public Demo(); 
        76.   Code: 
        77.    Stack=1, Locals=1, Args_size=1 
        78.    0:      aload_0 
        79.    1:      invokespecial  #18//Method java/lang/Object."<init>":()V 
        80.    4:      return 
        81.   LineNumberTable: 
        82.    line 20 
        83.   LocalVariableTable: 
        84.    Start  Length  Slot  Name   Signature 
        85.    0      5      0    this       LDemo; 
        86.   
        87. public void sayHello3(); 
        88.   Code: 
        89.    Stack=2, Locals=1, Args_size=1 
        90.    0:      getstatic   #25//Field java/lang/System.out:Ljava/io/PrintStream; 
        91.    3:      ldc   #43//String this is method3... 
        92.    5:      invokevirtual  #33//Method java/io/PrintStream.println:(Ljava/lang/String;)V 
        93.    8:      return 
        94.   LineNumberTable: 
        95.    line 170 
        96.    line 188 
        97.   LocalVariableTable: 
        98.    Start  Length  Slot  Name   Signature 
        99.    0      9      0    this       LDemo; 
        100. }
        101. 解析:

            1、版本號(hào) major version: 49 //java版本 jdk1.6顯示的是50, jdk1.5顯示的是49,jdk1.4顯示的是58 , 高版本能執(zhí)行低版本的class文件

            2、常量池Constant pool

            Method:方法

            Field:字段

            String:字符串

            Asciz:簽名如<init>由jvm調(diào)用,其他是不能夠去調(diào)用它的

            NameAndType:變量名的類(lèi)型

            Class:類(lèi)

            通過(guò)字節(jié)碼,我們可以看到Demo類(lèi) 繼承于java.lang.Object,如果類(lèi)中沒(méi)有顯式聲明構(gòu)造函數(shù)的話(huà),編譯器會(huì)插入一個(gè)缺省無(wú)參的構(gòu)造函數(shù)(構(gòu)造函數(shù)在JVM級(jí)別是顯示成<init>的普通函數(shù))。

            三:檢測(cè)代碼的效率問(wèn)題

            學(xué)習(xí)Java的過(guò)程中,都會(huì)了解到字符串合并時(shí)要用到StringBuffer 來(lái)代替String,那下面就來(lái)通過(guò)Java字節(jié)碼來(lái)驗(yàn)證兩種方式的效率性。

            例子:一個(gè)Java類(lèi) TestString.java

        102. <strong>public class TestString { 
        103.     public String testString(String str1, String str2){ 
        104.        return str1 + str2; 
        105.     } 
        106.     public String testStringBuffer(StringBuffer sb, String str){ 
        107.        return sb.append(str).toString(); 
        108.     } 
        109.  </strong>
        110.   javap –c TestString 后字節(jié)碼信息:

        111. Compiled from "TestString.java" 
        112. public class TestString extends java.lang.Object{ 
        113. public TestString(); 
        114.   Code: 
        115.    0:      aload_0 
        116.    1:      invokespecial  #8//Method java/lang/Object."<init>":()V 
        117.    4:      return 
        118.   
        119. public java.lang.String testString(java.lang.String, java.lang.String); 
        120.   Code: 
        121.    0:      new #16//class java/lang/StringBuilder 
        122.    3:      dup 
        123.    4:      aload_1 
        124.    5:      invokestatic    #18//Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 
        125.    8:      invokespecial  #24//Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 
        126.    11:     aload_2 
        127.    12:    invokevirtual  #27//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
        128.    15:    invokevirtual  #31//Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
        129.    18:    areturn 
        130.   
        131. public java.lang.String testStringBuffer(java.lang.StringBuffer, java.lang.String); 
        132.   Code: 
        133.    0:      aload_1 
        134.    1:      aload_2 
        135.    2:      invokevirtual  #40//Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; 
        136.    5:      invokevirtual  #45//Method java/lang/StringBuffer.toString:()Ljava/lang/String; 
        137.    8:      areturn 
        138. }
        139.   從上面編譯后的字節(jié)碼信息可以看出來(lái),方法testString 調(diào)用了五個(gè)方法:new 、invokestatic 、invokespecial 和兩個(gè)invokevirtual ; 而testStringBuffer 方法只調(diào)用了兩個(gè)invokevirtual 方法。第一個(gè)方法比第二個(gè)方法多做了好多工作,其效率當(dāng)然是要低的。而且我們從java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

            可以看出來(lái)其實(shí)對(duì)于String字符串合并,內(nèi)部還是轉(zhuǎn)化為StringBuilder的方法調(diào)用,這是因?yàn)镾tring是長(zhǎng)度不可變的,所以不如直接采用StringBuilder(與StringBuffer 長(zhǎng)度都是可變的,只不過(guò)前者是非線(xiàn)程安全,后者是線(xiàn)程安全)進(jìn)行字符串合并。





          posted on 2011-12-06 11:10 順其自然EVO 閱讀(7944) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2011年12月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類(lèi)

          隨筆檔案

          文章分類(lèi)

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 鸡西市| 西安市| 陵川县| 宁津县| 广宁县| 且末县| 西乌珠穆沁旗| 上饶市| 九龙县| 都兰县| 多伦县| 望都县| 裕民县| SHOW| 和平区| 汾西县| 乐都县| 长阳| 沽源县| 冀州市| 哈密市| 阳朔县| 许昌市| 城步| 台东市| 广水市| 彰化县| 潮州市| 阿巴嘎旗| 大竹县| 屯留县| 全椒县| 辰溪县| 察隅县| 孝义市| 绥芬河市| 宁强县| 江川县| 连南| 渭源县| 鹿泉市|