程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java字節碼深入解析

Java字節碼深入解析

編輯:關於JAVA

一:Java字節代碼的組織形式

類文件{

OxCAFEBABE,小版本號,大版本號,常量池大小,常量池數組,訪問控制標記,當前類信息,父類信息,實現的接口個數,實現的接口信息數組,域個數,域信息數組,方法個數,方法信息數組,屬性個數,屬性信息數組

}

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

例子:有一個Java類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. private void sayHello1(){
  8. System.out.println("this is method1...");
  9. }
  10. private void sayHello2(){
  11. System.out.println("this is method2...");
  12. }
  13. public void sayHello3(){
  14. System.out.println("this is method3...");
  15. }
  16. }

通過jdk自帶的反編譯工具命令 Javap 可以查看class文件的字節碼信息

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

Demo.txt:

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

解析:

1.版本號 major version: 49 //Java版本 jdk1.6顯示的是50, jdk1.5顯示的是49,jdk1.4顯示的是58 , 高版本能執行低版本的class文件

2.常量池Constant pool

Method:方法

FIEld:字段

String:字符串

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

NameAndType:變量名的類型

Class:類

通過字節碼,我們可以看到Demo類 繼承於Java.lang.Object,如果類中沒有顯式聲明構造函數的話,編譯器會插入一個缺省無參的構造函數(構造函數在JVM級別是顯示成<init>的普通函數)。

三:檢測代碼的效率問題

學習Java的過程中,都會了解到字符串合並時要用到StringBuffer 來代替String,那下面就來通過Java字節碼來驗證兩種方式的效率性。

例子:一個Java類 TestString.Java

  1. <strong>public class TestString {
  2. public String testString(String str1, String str2){
  3. return str1 + str2;
  4. }
  5. public String testStringBuffer(StringBuffer sb, String str){
  6. return sb.append(str).toString();
  7. }
  8. }
  9. </strong>

Javap –c TestString 後字節碼信息:

  1. Compiled from "TestString.Java"
  2. public class TestString extends Java.lang.Object{
  3. public TestString();
  4. Code:
  5. 0: aload_0
  6. 1: invokespecial #8; //Method Java/lang/Object."<init>":()V
  7. 4: return
  8. public java.lang.String testString(java.lang.String, Java.lang.String);
  9. Code:
  10. 0: new #16; //class Java/lang/StringBuilder
  11. 3: dup
  12. 4: aload_1
  13. 5: invokestatic #18; //Method java/lang/String.valueOf:(Ljava/lang/Object;)LJava/lang/String;
  14. 8: invokespecial #24; //Method java/lang/StringBuilder."<init>":(LJava/lang/String;)V
  15. 11: aload_2
  16. 12: invokevirtual #27; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)LJava/lang/StringBuilder;
  17. 15: invokevirtual #31; //Method java/lang/StringBuilder.toString:()LJava/lang/String;
  18. 18: areturn
  19. public java.lang.String testStringBuffer(java.lang.StringBuffer, Java.lang.String);
  20. Code:
  21. 0: aload_1
  22. 1: aload_2
  23. 2: invokevirtual #40; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)LJava/lang/StringBuffer;
  24. 5: invokevirtual #45; //Method java/lang/StringBuffer.toString:()LJava/lang/String;
  25. 8: areturn
  26. }

從上面編譯後的字節碼信息可以看出來,方法testString 調用了五個方法:new 、invokestatic 、invokespecial 和兩個invokevirtual ; 而testStringBuffer 方法只調用了兩個invokevirtual 方法。第一個方法比第二個方法多做了好多工作,其效率當然是要低的。而且我們從java/lang/StringBuilder.append:(Ljava/lang/String;)LJava/lang/StringBuilder;

可以看出來其實對於String字符串合並,內部還是轉化為StringBuilder的方法調用,這是因為String是長度不可變的,所以不如直接采用StringBuilder(與StringBuffer 長度都是可變的,只不過前者是非線程安全,後者是線程安全)進行字符串合並。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved