Java扫描字节码 Java字节码深入解析
Java字节码深入解析
一 Java字节代码的组织形式
类文件{
OxCAFEBABE 小版本号 大版本号 常量池大小 常量池数组 访问控制标记 当前类信息 父类信息 实现的接口个数 实现的接口信息数组 域个数 域信息数组 方法个数 方法信息数组 属性个数 属性信息数组
}
二 查看方法 javap命令
例子 有一个Java类Demo java
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 (){ System out println( this is method ); } private void sayHello (){ System out println( this is method ); } public void sayHello (){ System out println( this is method ); }} 通过jdk自带的反编译工具命令 javap 可以查看class文件的字节码信息
D:>javap verbose Demo >> Demo txt Demo txt
Compiled from Demo java public class Demo extends java lang Object SourceFile: Demo java minor version: major version:
Constant pool:const # = class # ; // Democonst # = Asciz Demo;const # = class # ; // java/lang/Objectconst # = 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 worldconst # = Asciz hello world;const # = Asciz <init>;const # = Asciz ()V;const # = Asciz Code;const # = Method # # ; // java/lang/Object <init> :()Vconst # = NameAndType # :# ;// <init> :()Vconst # = Asciz LineNumberTable;const # = Asciz LocalVariableTable;const # = Asciz this;const # = Asciz LDemo;;const # = Asciz sayHello ;const # = Field # # ; // java/lang/System out:Ljava/io/PrintStream;const # = class # ; // java/lang/Systemconst # = 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/PrintStream println:(Ljava/lang/String;)Vconst # = class # ; // java/io/PrintStreamconst # = Asciz java/io/PrintStream;const # = NameAndType # :# ;// println:(Ljava/lang/String;)Vconst # = 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 Demo java;
{public static final java lang String STATIC_DATA; Constant value: String hello worldpublic 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/System out:Ljava/io/PrintStream; : ldc # ; //String this is method : invokevirtual # ; //Method java/io/PrintStream println:(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类 继承于java lang Object 如果类中没有显式声明构造函数的话 编译器会插入一个缺省无参的构造函数(构造函数在JVM级别是显示成<init>的普通函数)
三 检测代码的效率问题
学习Java的过程中 都会了解到字符串合并时要用到StringBuffer 来代替String 那下面就来通过Java字节码来验证两种方式的效率性
例子 一个Java类 TestString java
<strong>public class TestString { public String testString(String str String str ){ return str + str ; } public String testStringBuffer(StringBuffer sb String str){ return sb append(str) toString(); }} </strong> javap –c TestString 后字节码信息
Compiled from TestString java public class TestString extends java lang Object{public TestString(); Code: : aload_ : invokespecial # ; //Method java/lang/Object <init> :()V : return
public java lang String testString(java lang String java lang String); Code: : new # ; //class java/lang/StringBuilder : dup : aload_ : invokestatic # ; //Method java/lang/String valueOf:(Ljava/lang/Object;)Ljava/lang/String; : invokespecial # ; //Method java/lang/StringBuilder <init> :(Ljava/lang/String;)V : aload_ : invokevirtual # ; //Method java/lang/StringBuilder append:(Ljava/lang/String;)Ljava/lang/StringBuilder; : invokevirtual # ; //Method java/lang/StringBuilder toString:()Ljava/lang/String; : areturn
public java lang String testStringBuffer(java lang StringBuffer java lang String); Code: : aload_ : aload_ : invokevirtual # ; //Method java/lang/StringBuffer append:(Ljava/lang/String;)Ljava/lang/StringBuffer; : invokevirtual # ; //Method java/lang/StringBuffer toString:()Ljava/lang/String; : areturn} 从上面编译后的字节码信息可以看出来 方法testString 调用了五个方法 new invokestatic invokespecial 和两个invokevirtual 而testStringBuffer 方法只调用了两个invokevirtual 方法 第一个方法比第二个方法多做了好多工作 其效率当然是要低的 而且我们从java/lang/StringBuilder append (Ljava/lang/String )Ljava/lang/StringBuilder
lishixinzhi/Article/program/Java/hx/201311/26098