a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 549|回复: 2

[专业语言] Java字节码深入解析

[复制链接]
发表于 2012-8-4 12:44:44 | 显示全部楼层 |阅读模式
一:Java字节代码的组织形式/ Q* Z! G0 q) F$ _5 }& }
  类文件{
8 ^7 H5 `# P( p5 X  OxCAFEBABE,小版本号,大版本号,常量池大小,常量池数组,访问控制标记,当前类信息,父类信息,实现的接口个数,实现的接口信息数组,域个数,域信息数组,方法个数,方法信息数组,属性个数,属性信息数组8 N  `5 {' E5 K, j/ C
  }
5 X( f# T) n- `6 z  二:查看方法 --- javap命令
# Q: k! E# j$ I/ b  例子:有一个Java类Demo.java* s. h7 p: p: j7 S9 `  T; V
public class Demo {
" C/ q$ ~: W* s, G# F% l/ t- A    private String str1;1 a4 Q1 j/ E  N, ^" L: V
    private String str2;
" p. P8 c% o0 y% W' }    private int num1;( b: ^3 ~( b% l) Z, B2 S
    private int num2;3 V4 c0 b, Z: q1 I" R
    public static final String STATIC_DATA = "hello world";
4 s( j9 T) `! U( O: d$ a' ]    private void sayHello1(){
0 b! y3 P6 l3 p3 q9 |        System.out.println("this is method1...");
- p4 R0 O, T" D. N9 S    }% B% C% \1 U) A8 _" q* R" ~
    private void sayHello2(){
8 T$ r8 t& Q( b7 U        System.out.println("this is method2...");
4 Z! f& Z* D8 N& M! Z    }
+ c1 Z  v; r6 ?! }. E: A    public void sayHello3(){
- r. n& N" W- s        System.out.println("this is method3...");! T* W& H& |% y  p
    }
' n/ Q5 G% G" K0 v) K3 m' q}
2 |" P6 W5 X8 O% ~* K  通过jdk自带的反编译工具命令 javap 可以查看class文件的字节码信息% i; ~$ u( o6 `& [
D:\>javap -verbose Demo >> Demo.txt  P- c7 H/ y: \! x$ u' h
  Demo.txt:
( x* B& Z3 {/ D5 X4 H  ~Compiled from "Demo.java"2 y0 ^9 f- P" }$ [1 O( L  ^6 e
public class Demo extends java.lang.Object
" d" D  C1 x3 i) J1 y7 U  SourceFile: "Demo.java"
3 Y! y1 z1 w( n  minor version: 09 p, ]  t9 j: U3 }/ J/ ?: N
  major version: 49! {4 u/ y5 e) W
  Constant pool:
/ ~. z. c: `, |4 j/ S- m2 q0 {const #1 = class      #2;   //  Demo# r' y7 c7 Y# U& B) E( F
const #2 = Asciz     Demo;0 r& M/ U, C  _8 Q. @
const #3 = class      #4;   //  java/lang/Object* N) C/ I  v$ ^: n9 u2 ?3 A; p1 L2 G' r
const #4 = Asciz     java/lang/Object;" ^  r2 l) U5 O. ~$ f1 X
const #5 = Asciz     str1;% v0 M% H* [- I9 e
const #6 = Asciz     Ljava/lang/String;;$ u/ Q4 L* v0 y
const #7 = Asciz     str2;  y$ K! M2 M3 K4 Z& j
const #8 = Asciz     num1;
9 @- \) k# A( P4 Q. l" `const #9 = Asciz     I;# [0 ^2 t% C. f6 v$ h
const #10 = Asciz   num2;# L& Z5 W7 n% Q4 Z
const #11 = Asciz   STATIC_DATA;
% H7 J0 y' ?% f3 W4 F5 q1 bconst #12 = Asciz   ConstantValue;
9 i9 W' }+ q& r7 Yconst #13 = String  #14; //  hello world: D. e$ n: W, t2 Y, @
const #14 = Asciz   hello world;
2 w# L6 k2 J7 L8 ~1 S% }const #15 = Asciz   ;
/ R" f& j7 u& m- ~% jconst #16 = Asciz   ()V;
! L" t$ X2 m( d6 s2 a4 vconst #17 = Asciz   Code;
; y2 @& i% S$ A) X: I0 {! Xconst #18 = Method       #3.#19;   //  java/lang/Object."":()V+ z2 W. |. |2 E- E+ I7 [
const #19 = NameAndType    #15:#16;//  "":()V* |7 D2 b' ]; u. g/ a6 R* D3 {( W0 _
const #20 = Asciz   LineNumberTable;
9 O1 e# z: U, y* ?. |4 N' B) H5 cconst #21 = Asciz   LocalVariableTable;3 X$ n& x: S% L$ f
const #22 = Asciz   this;/ N! q( F1 N& y& p
const #23 = Asciz   LDemo;;
8 l. v% B4 _& }% R. p# D  @6 C. b! kconst #24 = Asciz   sayHello1;
9 N. m7 o) ^* f6 z% f3 o2 yconst #25 = Field   #26.#28;  //  java/lang/System.out:Ljava/io/PrintStream;) b( ^& z. x! P6 V
const #26 = class    #27; //  java/lang/System$ }* ^9 Y1 @# q
const #27 = Asciz   java/lang/System;& w. \: J) F# N7 S
const #28 = NameAndType    #29:#30;//  out:Ljava/io/PrintStream;
0 E! {+ N7 _. A/ u% Q* `( ~6 cconst #29 = Asciz   out;: S4 U/ Z% U9 `% t& _- _
const #30 = Asciz   Ljava/io/PrintStream;;2 x" q! F% ^' l. ?
const #31 = String  #32; //  this is method1...  h$ b% L: o1 L
const #32 = Asciz   this is method1...;
( C2 g$ p3 q1 l8 K6 y" xconst #33 = Method       #34.#36;  //  java/io/PrintStream.println:(Ljava/lang/String;)V
2 `# u; q. z5 E/ qconst #34 = class    #35; //  java/io/PrintStream. Y+ b/ E2 @+ x; I' w
const #35 = Asciz   java/io/PrintStream;
0 g, t# Z6 N* R4 qconst #36 = NameAndType    #37:#38;//  println:(Ljava/lang/String;)V
# r+ b2 K. t0 T4 yconst #37 = Asciz   println;+ a2 _  m. r, n( h
const #38 = Asciz   (Ljava/lang/String;)V;: N& m8 ]6 \; S0 p- e, k. @$ @
const #39 = Asciz   sayHello2;
$ V$ H  K! U: I7 B1 K! Qconst #40 = String  #41; //  this is method2...& z1 c3 B- |8 Q5 @( e0 _/ l
const #41 = Asciz   this is method2...;
; z5 T5 F- _7 Sconst #42 = Asciz   sayHello3;' D# G  u: c4 A, `. b
const #43 = String  #44; //  this is method3...4 t( z6 @3 ~5 J! ~0 |
const #44 = Asciz   this is method3...;  u8 u2 m, K- A/ l9 Z
const #45 = Asciz   SourceFile;
" b& b' ^9 @; m/ W2 Rconst #46 = Asciz   Demo.java;
; W2 m$ j7 Q" d' d; x( l" b/ g! h* t" [
{
, T+ Q" X( V# y/ Z* Kpublic static final java.lang.String STATIC_DATA;
& D5 Y( @' _2 O4 K3 J  Constant value: String hello world* Y- P. y) e$ ]
public Demo();4 r3 w9 k, K' V2 ?
  Code:
7 ~4 O1 {1 s' ^& B7 Q- Z   Stack=1, Locals=1, Args_size=1
+ E4 t; Y+ d% ~3 K) d2 r1 t$ B: @   0:      aload_0
. i0 n9 i. a4 p" u! H( v   1:      invokespecial  #18; //Method java/lang/Object."
回复

使用道具 举报

 楼主| 发表于 2012-8-4 12:44:45 | 显示全部楼层

Java字节码深入解析

":()V
& X+ }8 d) G* w1 |; U- h   4:      return
0 @* O% Y; D, H  LineNumberTable:4 L2 ~  G* F) L; K$ e# r
   line 2: 09 S' O3 Z/ s5 k  z& i
  LocalVariableTable:) l) X! c5 o+ R* ?  }
   Start  Length  Slot  Name   Signature
% e; Z! c8 Y( {  ^: W/ ^6 ^   0      5      0    this       LDemo;</p>public void sayHello3();. T6 A, Q0 O# s) [* r
  Code:' p# [) n, |  m1 ?
   Stack=2, Locals=1, Args_size=1
0 G7 s% ^1 q1 S) g) U5 n5 a8 j   0:      getstatic   #25; //Field java/lang/System.out:Ljava/io/PrintStream;
# v2 i( n2 y; g9 M% J   3:      ldc   #43; //String this is method3...
8 x( g' @) u  [7 @# o$ y" h8 e   5:      invokevirtual  #33; //Method java/io/PrintStream.println:(Ljava/lang/String;)V, N# I( o& r. K: K) \
   8:      return
" H4 Y2 d4 l) `7 w4 w% A  LineNumberTable:* [  E9 t0 G& x: ?
   line 17: 03 d. n3 \  S1 H! u
   line 18: 8
$ E( ^/ X8 N. B# H4 O  LocalVariableTable:$ N% w1 K/ C/ g0 v( R# t  R
   Start  Length  Slot  Name   Signature7 p8 m: u; e3 I' u6 Q9 t  z. ~
   0      9      0    this       LDemo;
4 V) s5 W$ C+ f4 Z}
5 q) h0 U% @, R3 s9 u解析:% s+ |" I/ u: v( ^: `' f# V
  1、版本号 major version: 49 //java版本 jdk1.6显示的是50, jdk1.5显示的是49,jdk1.4显示的是58 , 高版本能执行低版本的class文件' t- F' C1 K! q9 @- B
  2、常量池Constant pool
7 C+ i' h' `+ l; H8 c  Method:方法' ]0 a8 N# ^/ D6 i* F0 t0 z# T7 h" P
  Field:字段
4 F) A. ?6 |9 @  String:字符串% |: G, ]% P9 g  M' d1 B
  Asciz:签名如由jvm调用,其他是不能够去调用它的2 C; I. s9 D) ]9 a3 z0 M/ ~' c
  NameAndType:变量名的类型
. B; u0 @+ i# X  Class:类
8 }' M! X  y0 q  通过字节码,我们可以看到Demo类 继承于java.lang.Object,如果类中没有显式声明构造函数的话,编译器会插入一个缺省无参的构造函数(构造函数在JVM级别是显示成的普通函数)。
/ E4 Z" _- K* C0 p  三:检测代码的效率问题$ ^  E* Y# O5 }6 k$ V- h
  学习Java的过程中,都会了解到字符串合并时要用到StringBuffer 来代替String,那下面就来通过Java字节码来验证两种方式的效率性。
# ]8 ^+ R/ `! I9 ?$ Q; ]  例子:一个Java类 TestString.java4 I' X! |' i" K7 ~3 v
public class TestString {
# c+ l  z' X( r: ~4 s4 \    public String testString(String str1, String str2){
  l1 z" |" B& b3 X( c8 l7 \       return str1 + str2;8 h2 o. o( [6 Z4 _
    }
1 Y( Z+ {) }8 p# J) C: Z    public String testStringBuffer(StringBuffer sb, String str){
, B$ z  n, I8 g7 J% y       return sb.append(str).toString();' j  p6 S% W% _: c' i1 F% h* h
    }5 ?8 ~- T6 N( `
}: x  ^5 o- H7 |0 A0 k
8 q* }$ L) s3 E% s
  javap –c TestString 后字节码信息:- K; H1 B  k8 @0 y  Y. G7 x2 x6 B$ Y
Compiled from "TestString.java"
  ?# k" Z6 m& d# C+ z( e; epublic class TestString extends java.lang.Object{
% D) M) T) N4 K- @public TestString();' z0 ?8 f% a7 T
  Code:
; P. s' M% x2 z, n   0:      aload_0
6 K2 R9 L0 N( f+ C6 O   1:      invokespecial  #8; //Method java/lang/Object."":()V
2 f, \% V' {  P; T; `9 v7 j   4:      return' L/ o4 m6 W/ v' J- f9 g  K  b
public java.lang.String testString(java.lang.String, java.lang.String);
- h+ ~1 T. O( N2 G  ~6 L  Code:) z! }! K# ?0 W! P6 Q, _* I' s
   0:      new #16; //class java/lang/StringBuilder* N3 _9 m% u, ?/ P# f
   3:      dup$ ]* S- O5 K% D' C9 s9 @' L( C
   4:      aload_1  _5 i3 Z5 P, p  H0 q
   5:      invokestatic    #18; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
/ H% h) u+ @, q3 p   8:      invokespecial  #24; //Method java/lang/StringBuilder."":(Ljava/lang/String;)V
. U1 |  S. H7 e. ~8 a5 H8 D- {   11:     aload_2
% _& g+ T7 b3 U* u+ J   12:    invokevirtual  #27; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
* I; v5 {" F: n9 u   15:    invokevirtual  #31; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
# c8 l& [7 C) f  e   18:    areturn
5 B( z. e1 }/ i0 n
% u" y, M+ X! d: R9 `+ N7 g- X) opublic java.lang.String testStringBuffer(java.lang.StringBuffer, java.lang.String);  c/ G9 p( ~4 r1 B, x9 `
  Code:
! k: H! ]9 {$ }+ _, Q" r+ f6 @2 Y# I   0:      aload_1
1 W# G+ }+ X4 H7 B: f9 j, B   1:      aload_22 N6 J# M; k% d
   2:      invokevirtual  #40; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
6 j( T0 h! u0 u3 y   5:      invokevirtual  #45; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;* `" g+ g  x: x4 `
   8:      areturnwww.ExamW.CoM# H0 R8 a4 Q! Q  q0 O" f% M# X
}
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-4 12:44:46 | 显示全部楼层

Java字节码深入解析

  从上面编译后的字节码信息可以看出来,方法testString 调用了五个方法:new 、invokestatic 、invokespecial 和两个invokevirtual ; 而testStringBuffer 方法只调用了两个invokevirtual 方法。第一个方法比第二个方法多做了好多工作,其效率当然是要低的。而且我们从java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;</p>  可以看出来其实对于String字符串合并,内部还是转化为StringBuilder的方法调用,这是因为String是长度不可变的,所以不如直接采用StringBuilder(与StringBuffer 长度都是可变的,只不过前者是非线程安全,后者是线程安全)进行字符串合并。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-4-25 02:10 , Processed in 0.358232 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表