熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

Java字節碼深入解析

2022-06-13   來源: Java核心技術 

  一Java字節代碼的組織形式

  類文件{

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

  }

  二查看方法 javap命令

  例子有一個Java類Demojava

  public class Demo {
    private String str;
    private String str;
    private int num;
    private int num;
    public static final String STATIC_DATA = hello world;

  private void sayHello(){
        Systemoutprintln(this is method);
    }
    private void sayHello(){
        Systemoutprintln(this is method);
    }
    public void sayHello(){
        Systemoutprintln(this is method);
    }
}
  通過jdk自帶的反編譯工具命令 javap 可以查看class文件的字節碼信息

  D:\>javap verbose Demo >> Demotxt
  Demotxt

  Compiled from Demojava
public class Demo extends javalangObject
  SourceFile: Demojava
  minor version:
  major version:

  Constant pool:
const # = class      #;   //  Demo
const # = Asciz     Demo;
const # = class      #;   //  java/lang/Object
const # = Asciz     java/lang/Object;
const # = Asciz     str;
const # = Asciz     Ljava/lang/String;;
const # = Asciz     str;
const # = Asciz     num;
const # = Asciz     I;
const # = Asciz   num;
const # = Asciz   STATIC_DATA;
const # = Asciz   ConstantValue;
const # = String  #; //  hello world
const # = Asciz   hello world;
const # = Asciz   <init>;
const # = Asciz   ()V;
const # = Asciz   Code;
const # = Method       ##;   //  java/lang/Object<init>:()V
const # = NameAndType    #:#;//  <init>:()V
const # = Asciz   LineNumberTable;
const # = Asciz   LocalVariableTable;
const # = Asciz   this;
const # = Asciz   LDemo;;
const # = Asciz   sayHello;
const # = Field   ##;  //  java/lang/Systemout:Ljava/io/PrintStream;
const # = class    #; //  java/lang/System
const # = Asciz   java/lang/System;
const # = NameAndType    #:#;//  out:Ljava/io/PrintStream;
const # = Asciz   out;
const # = Asciz   Ljava/io/PrintStream;;
const # = String  #; //  this is method
const # = Asciz   this is method;
const # = Method       ##;  //  java/io/PrintStreamprintln:(Ljava/lang/String;)V
const # = class    #; //  java/io/PrintStream
const # = Asciz   java/io/PrintStream;
const # = NameAndType    #:#;//  println:(Ljava/lang/String;)V
const # = Asciz   println;
const # = Asciz   (Ljava/lang/String;)V;
const # = Asciz   sayHello;
const # = String  #; //  this is method
const # = Asciz   this is method;
const # = Asciz   sayHello;
const # = String  #; //  this is method
const # = Asciz   this is method;
const # = Asciz   SourceFile;
const # = Asciz   Demojava;

  {
public static final javalangString STATIC_DATA;
  Constant value: String hello world
public Demo();
  Code:
   Stack= Locals= Args_size=
   :      aload_
   :      invokespecial  #; //Method java/lang/Object<init>:()V
   :      return
  LineNumberTable:
   line :
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
                   this       LDemo;

  public void sayHello();
  Code:
   Stack= Locals= Args_size=
   :      getstatic   #; //Field java/lang/Systemout:Ljava/io/PrintStream;
   :      ldc   #; //String this is method
   :      invokevirtual  #; //Method java/io/PrintStreamprintln:(Ljava/lang/String;)V
   :      return
  LineNumberTable:
   line :
   line :
  LocalVariableTable:
   Start  Length  Slot  Name   Signature
                   this       LDemo;
}

  解析

  版本號 major version //java版本 jdk顯示的是 jdk顯示的是jdk顯示的是 高版本能執行低版本的class文件

  常量池Constant pool

  Method方法

  Field字段

  String字符串

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

  NameAndType變量名的類型

  Class

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

  三檢測代碼的效率問題

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

  例子一個Java類 TestStringjava

  <strong>public class TestString {
    public String testString(String str String str){
       return str + str;
    }
    public String testStringBuffer(StringBuffer sb String str){
       return sbappend(str)toString();
    }
}
 </strong>
  javap –c TestString 後字節碼信息

  Compiled from TestStringjava
public class TestString extends javalangObject{
public TestString();
  Code:
   :      aload_
   :      invokespecial  #; //Method java/lang/Object<init>:()V
   :      return

  public javalangString testString(javalangString javalangString);
  Code:
   :      new #; //class java/lang/StringBuilder
   :      dup
   :      aload_
   :      invokestatic    #; //Method java/lang/StringvalueOf:(Ljava/lang/Object;)Ljava/lang/String;
   :      invokespecial  #; //Method java/lang/StringBuilder<init>:(Ljava/lang/String;)V
   :     aload_
   :    invokevirtual  #; //Method java/lang/StringBuilderappend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   :    invokevirtual  #; //Method java/lang/StringBuildertoString:()Ljava/lang/String;
   :    areturn

  public javalangString testStringBuffer(javalangStringBuffer javalangString);
  Code:
   :      aload_
   :      aload_
   :      invokevirtual  #; //Method java/lang/StringBufferappend:(Ljava/lang/String;)Ljava/lang/StringBuffer;
   :      invokevirtual  #; //Method java/lang/StringBuffertoString:()Ljava/lang/String;
   :      areturn
}
  從上面編譯後的字節碼信息可以看出來方法testString 調用了五個方法new invokestatic invokespecial 和兩個invokevirtual 而testStringBuffer 方法只調用了兩個invokevirtual 方法第一個方法比第二個方法多做了好多工作其效率當然是要低的而且我們從java/lang/StringBuilderappend(Ljava/lang/String)Ljava/lang/StringBuilder

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


From:http://tw.wingwit.com/Article/program/Java/hx/201311/26098.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.