[公告] 问一个javap查看字节码的问题

michael9527 2012-04-19
使用javap查看字节码发现一个奇怪的问题,
在centos(使用的是JDK是 HotSpot  1.6.0_29) 和
windows xp(使用的JDK是 HotSpot 1.6.0_31)
centos和windows上javap的结果都是一样的

写了一个测试类,如下:
package com.test;

public class MyClass implements Runnable {


	public boolean boolean_value = true;
	public byte byte_value = 33;
	public short short_value = 1;
	public char char_vlaue = 'a';
	public int int_value = 234567;
	public long long_value = 100L;
	public float float_value = 3.33F;
	public double double_value = 3.1415;
	
	public String ss = "12345";
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}
	
	public void run() {
		
	}

	
	public void xx() {
		Runnable r = this;
		r.run();
	}
}




javap -verbose MyClass 内容为:(只列出了常量池部分,其余的省略了)

F:\>javap -verbose MyClass
Compiled from "MyClass.java"
public class com.test.MyClass extends java.lang.Object implements java.lang.Runn
able
  SourceFile: "MyClass.java"
  minor version: 0
  major version: 50
  Constant pool:
const #1 = class        #2;     //  com/test/MyClass
const #2 = Asciz        com/test/MyClass;
const #3 = class        #4;     //  java/lang/Object
const #4 = Asciz        java/lang/Object;
const #5 = class        #6;     //  java/lang/Runnable
const #6 = Asciz        java/lang/Runnable;
const #7 = Asciz        boolean_value;
const #8 = Asciz        Z;
const #9 = Asciz        byte_value;
const #10 = Asciz       B;
const #11 = Asciz       short_value;
const #12 = Asciz       S;
const #13 = Asciz       char_vlaue;
const #14 = Asciz       C;
const #15 = Asciz       int_value;
const #16 = Asciz       I;
const #17 = Asciz       long_value;
const #18 = Asciz       J;
const #19 = Asciz       float_value;
const #20 = Asciz       F;
const #21 = Asciz       double_value;
const #22 = Asciz       D;
const #23 = Asciz       ss;
const #24 = Asciz       Ljava/lang/String;;
const #25 = Asciz       <init>;
const #26 = Asciz       ()V;
const #27 = Asciz       Code;
const #28 = Method      #3.#29; //  java/lang/Object."<init>":()V
const #29 = NameAndType #25:#26;//  "<init>":()V
const #30 = Field       #1.#31; //  com/test/MyClass.boolean_value:Z
const #31 = NameAndType #7:#8;//  boolean_value:Z
const #32 = Field       #1.#33; //  com/test/MyClass.byte_value:B
const #33 = NameAndType #9:#10;//  byte_value:B
const #34 = Field       #1.#35; //  com/test/MyClass.short_value:S
const #35 = NameAndType #11:#12;//  short_value:S
const #36 = Field       #1.#37; //  com/test/MyClass.char_vlaue:C
const #37 = NameAndType #13:#14;//  char_vlaue:C
const #38 = int 234567;
const #39 = Field       #1.#40; //  com/test/MyClass.int_value:I
const #40 = NameAndType #15:#16;//  int_value:I
const #41 = long        100l;
const #43 = Field       #1.#44; //  com/test/MyClass.long_value:J
const #44 = NameAndType #17:#18;//  long_value:J
const #45 = float       3.33f;
const #46 = Field       #1.#47; //  com/test/MyClass.float_value:F
const #47 = NameAndType #19:#20;//  float_value:F
const #48 = double      3.1415d;
const #50 = Field       #1.#51; //  com/test/MyClass.double_value:D
const #51 = NameAndType #21:#22;//  double_value:D
const #52 = String      #53;    //  12345
const #53 = Asciz       12345;
const #54 = Field       #1.#55; //  com/test/MyClass.ss:Ljava/lang/String;
const #55 = NameAndType #23:#24;//  ss:Ljava/lang/String;
const #56 = Asciz       LineNumberTable;
const #57 = Asciz       LocalVariableTable;
const #58 = Asciz       this;
const #59 = Asciz       Lcom/test/MyClass;;
const #60 = Asciz       main;
const #61 = Asciz       ([Ljava/lang/String;)V;
const #62 = Asciz       args;
const #63 = Asciz       [Ljava/lang/String;;
const #64 = Asciz       run;
const #65 = Asciz       xx;
const #66 = InterfaceMethod     #5.#67; //  java/lang/Runnable.run:()V
const #67 = NameAndType #64:#26;//  run:()V
const #68 = Asciz       r;
const #69 = Asciz       Ljava/lang/Runnable;;
const #70 = Asciz       SourceFile;
const #71 = Asciz       MyClass.java;



注意看这个常量池的下标增长顺序, 没有42,也没有49。

查看Myclass.class,前10个字节是:
CA FE BA BE 00 00 00 32 00 48
也就是一共有71一个常量,从下标个数来看是对的,但不明白为何显示的时候少了42和49?

此外还有一问题,从源码中看我定义了这几个变量:
	public byte byte_value = 33;
	public short short_value = 1;
	public char char_vlaue = 'a';

不过从字节码显示结果看,并没有33,1,'a'这些相关的信息,但如果用一些反编译工具的话,编译后的java和源码结果是可以对应上的,所以不清楚这些信息是存在哪里了?还是说javap就没有显示出来?
RednaxelaFX 2012-04-19
短整型常量是直接嵌在指令里的。
例如
iconst_<n>,n从-1到5
bipush,用来load一个字节宽的整数常量
sipush,用来load两个字节宽的整数常量
在short范围之外的整数常量才会出现在常量池里。

你看到常量池里有些下标缺失,是因为long和double是占两个相邻的项的…这个例子里41和48一个是long一个是double,所以42和49就没了。
michael9527 2012-04-19
public com.test.MyClass();
  Code:
   Stack=3, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #28; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   iconst_1
   6:   putfield        #30; //Field boolean_value:Z
   9:   aload_0
   10:  bipush  33
   12:  putfield        #32; //Field byte_value:B
   15:  aload_0
   16:  iconst_1
   17:  putfield        #34; //Field short_value:S
   20:  aload_0
   21:  bipush  97
   23:  putfield        #36; //Field char_vlaue:C


呵呵,只关注常量池,没想到内嵌到指令里了,另外发现如果变量定义为final的,也会出现在常量池里。多谢R大。
Global site tag (gtag.js) - Google Analytics