java String 之字节码解析

关于java  string 的面试题有很多。。。网上的说法也有很多中。。。。

 在这我解析一下string 的用法的字节码。。。。

public class C{
		public C(){

		}
	public C(String a){
		 this.str=a;
		}
	
 String str0 = "min0";	
 static	String str = "min";
 static	String str2 = "min2";
 final	String str3 = "minmin2";
 final String str4 = "min3";
 public void t(int b){
		System.out.println("min"+str2);
		System.out.println("t--"+str3);
		System.out.println(str4+str3);
		System.out.println(str0+str);
	}
	public static void main(String[] args) {
		new A().t(2);
	
	}

}

   通过javap -verbose 查看一下字节码的存储信息如下

Compiled from "C.java"
public class C extends java.lang.Object
  SourceFile: "C.java"
  minor version: 0 //class文件的次版本号
  major version: 49//class文件的主版本号
  Constant pool://常量池
  
//Method:方法 
 //Field:字段 
 //String:字符串 
 //Asciz:这个Asciz表示是CONSTANT_Utf8吧,因为C ONSTANT_Utf8可以是存储四种基本信息类型:文字字符串、被定义的类和接口描述、对其他类或接口的符号引用以及属性相关的字符串。 
 //NameAndType:变量名的类型 
 //Class:类 
  
const #1 = Method       #24.#44;        //  java/lang/Object."<init>":()V //CONSTANT_Methodref_info (10)
const #2 = String       #45;    //  min0     //字符串常量池中的常量 CONSTANT_String_info (8)
const #3 = Field        #23.#46;        //  C.str0:Ljava/lang/String;//没有static修饰的字段记录字段信息
const #4 = String       #47;    //  minmin2  //字符串常量池中的常量 CONSTANT_String_info (8)
const #5 = Field        #23.#48;        //  C.str3:Ljava/lang/String;//没有static修饰的字段
const #6 = String       #49;    //  min3    //字符串常量池中的常量
const #7 = Field        #23.#50;        //  C.str4:Ljava/lang/String;//没有static修饰的字段
const #8 = Field        #23.#51;        //  C.str:Ljava/lang/String;//static修饰的字段
const #9 = Field        #52.#53;        //  java/lang/System.out:Ljava/io/PrintS
tream;
const #10 = class       #54;    //  java/lang/StringBuilder 用于记录类或接口名CONSTANT_Class_info
const #11 = Method      #10.#44;        //  java/lang/StringBuilder."<init>":()V//用于记录方法信息 CONSTANT_Methodref_info

const #12 = String      #55;    //  min    //字符串常量池中的常量CONSTANT_String_info (8)
const #13 = Method      #10.#56;        //  java/lang/StringBuilder.append:(Ljav
a/lang/String;)Ljava/lang/StringBuilder;////用于记录方法信息 CONSTANT_Methodref_info
const #14 = Field       #23.#57;        //  C.str2:Ljava/lang/String;//static修饰的字段
const #15 = Method      #10.#58;        //  java/lang/StringBuilder.toString:()L
java/lang/String;
const #16 = Method      #59.#60;        //  java/io/PrintStream.println:(Ljava/l
ang/String;)V
const #17 = String      #61;    //  t--minmin2   //字符串常量池中的常量
const #18 = String      #62;    //  min3minmin2  //字符串常量池中的常量
const #19 = class       #63;    //  A
const #20 = Method      #19.#44;        //  A."<init>":()V
const #21 = Method      #19.#64;        //  A.t:(I)V
const #22 = String      #65;    //  min2
const #23 = class       #66;    //  C
const #24 = class       #67;    //  java/lang/Object
const #25 = Asciz       str0;
const #26 = Asciz       Ljava/lang/String;;
const #27 = Asciz       str;
const #28 = Asciz       str2;
const #29 = Asciz       str3;
const #30 = Asciz       ConstantValue;
const #31 = Asciz       str4;
const #32 = Asciz       <init>;
const #33 = Asciz       ()V;
const #34 = Asciz       Code;
const #35 = Asciz       LineNumberTable;
const #36 = Asciz       (Ljava/lang/String;)V;
const #37 = Asciz       t;
const #38 = Asciz       (I)V;
const #39 = Asciz       main;
const #40 = Asciz       ([Ljava/lang/String;)V;
const #41 = Asciz       <clinit>;
const #42 = Asciz       SourceFile;
const #43 = Asciz       C.java;
const #44 = NameAndType #32:#33;//  "<init>":()V//记录方法或字段的名称(name)和描述符(descriptor)
const #45 = Asciz       min0;
const #46 = NameAndType #25:#26;//  str0:Ljava/lang/String;// CONSTANT_NameAndType_info
const #47 = Asciz       minmin2;
const #48 = NameAndType #29:#26;//  str3:Ljava/lang/String;
const #49 = Asciz       min3;
const #50 = NameAndType #31:#26;//  str4:Ljava/lang/String;
const #51 = NameAndType #27:#26;//  str:Ljava/lang/String;
const #52 = class       #68;    //  java/lang/System
const #53 = NameAndType #69:#70;//  out:Ljava/io/PrintStream;
const #54 = Asciz       java/lang/StringBuilder;
const #55 = Asciz       min;
const #56 = NameAndType #71:#72;//  append:(Ljava/lang/String;)Ljava/lang/String
Builder;
const #57 = NameAndType #28:#26;//  str2:Ljava/lang/String;
const #58 = NameAndType #73:#74;//  toString:()Ljava/lang/String;
const #59 = class       #75;    //  java/io/PrintStream
const #60 = NameAndType #76:#36;//  println:(Ljava/lang/String;)V
const #61 = Asciz       t--minmin2;
const #62 = Asciz       min3minmin2;
const #63 = Asciz       A;
const #64 = NameAndType #37:#38;//  t:(I)V
const #65 = Asciz       min2;
const #66 = Asciz       C;
const #67 = Asciz       java/lang/Object;
const #68 = Asciz       java/lang/System;
const #69 = Asciz       out;
const #70 = Asciz       Ljava/io/PrintStream;;
const #71 = Asciz       append;
const #72 = Asciz       (Ljava/lang/String;)Ljava/lang/StringBuilder;;
const #73 = Asciz       toString;
const #74 = Asciz       ()Ljava/lang/String;;
const #75 = Asciz       java/io/PrintStream;
const #76 = Asciz       println;

{
java.lang.String str0;

static java.lang.String str;

static java.lang.String str2;

final java.lang.String str3;
  Constant value: String minmin2
final java.lang.String str4;
  Constant value: String min3
  
//如下的Locals表示方法内局部变量个数,该例中是1,有些人疑惑的是Dog()中明明没有参数啊,应该是0啊!      
//当线程调用一个方法的时候,jvm会开辟一个帧出来,这个帧包括操作栈、局部变量列表、常量池的引用      
//非static方法,在调用的时候都会给方法默认加上一个当前对象(this)类型的参数,不需要在方法中定义,      
//这个时候局部变量列表中index为0的位置保存的是this,其他索引号按变量定义顺序累加      
//static方法不依赖对象,所以不用传this      
//Args_size表示参数个数,public C();会传一个this进去,所以value是1    
public C();
  Code:
   Stack=2, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V //调用父类的构造函数
   4:   aload_0
   5:   ldc     #2; //String min0
   7:   putfield        #3; //Field str0:Ljava/lang/String;
   10:  aload_0
   11:  ldc     #4; //String minmin2
   13:  putfield        #5; //Field str3:Ljava/lang/String;
   16:  aload_0
   17:  ldc     #6; //String min3
   19:  putfield        #7; //Field str4:Ljava/lang/String;
   22:  return
  LineNumberTable:
   line 6: 0
   line 14: 4
   line 17: 10
   line 18: 16
   line 8: 22

//invokespecial  //调用构造方法、父类方法      
invokevirtual  //调用普通方法(非构造方法、static方法)      
invokestatic   //调用static方法    
public C(java.lang.String);
  Code:
   Stack=2, Locals=2, Args_size=2
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V //调用父类构造方法
   4:   aload_0
   5:   ldc     #2; //String min0 //将将常量池中的常量压入方法栈
   7:   putfield        #3; //Field str0:Ljava/lang/String;
   10:  aload_0
   11:  ldc     #4; //String minmin2
   13:  putfield        #5; //Field str3:Ljava/lang/String;
   16:  aload_0
   17:  ldc     #6; //String min3
   19:  putfield        #7; //Field str4:Ljava/lang/String;
   22:  aload_0
   23:  pop
   24:  aload_1
   25:  putstatic       #8; //Field str:Ljava/lang/String;
   28:  return
  LineNumberTable:
   line 10: 0
   line 14: 4
   line 17: 10
   line 18: 16
   line 11: 22
   line 12: 28

public void t(int);
  Code:
   Stack=3, Locals=2, Args_size=2
   0:   getstatic       #9; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   new     #10; //class java/lang/StringBuilder  //在堆中分配内存,返回对象引用,压入操作数栈   
   6:   dup   //复制引用到stack(栈) 
   7:   invokespecial   #11; //Method java/lang/StringBuilder."<init>":()V //调用构造方法
   10:  ldc     #12; //String min //将将常量池中的常量压入栈   
   12:  invokevirtual   #13; //Method java/lang/StringBuilder.append:(Ljava/lang 
/String;)Ljava/lang/StringBuilder; //调用方法
   15:  getstatic       #14; //Field str2:Ljava/lang/String;//访问static字段
   18:  invokevirtual   #13; //Method java/lang/StringBuilder.append:(Ljava/lang
/String;)Ljava/lang/StringBuilder;//调用方法
   21:  invokevirtual   #15; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;//调用方法
   24:  invokevirtual   #16; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V//调用方法
   27:  getstatic       #9; //Field java/lang/System.out:Ljava/io/PrintStream;//访问static字段
   30:  ldc     #17; //String t--minmin2 //将常量池中的常量压入栈
   32:  invokevirtual   #16; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V//调用方法
   35:  getstatic       #9; //Field java/lang/System.out:Ljava/io/PrintStream;
   38:  ldc     #18; //String min3minmin2  //将常量池中的常量压入栈
   40:  invokevirtual   #16; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V//调用方法
   43:  getstatic       #9; //Field java/lang/System.out:Ljava/io/PrintStream;//访问static字段
   46:  new     #10; //class java/lang/StringBuilder //在堆中分配内存,返回对象引用,压入操作数栈  
   49:  dup
   50:  invokespecial   #11; //Method java/lang/StringBuilder."<init>":()V//调用方法
   53:  aload_0
   54:  getfield        #3; //Field str0:Ljava/lang/String;//访问str0字段
   57:  invokevirtual   #13; //Method java/lang/StringBuilder.append:(Ljava/lang
/String;)Ljava/lang/StringBuilder;//调用方法
   60:  getstatic       #8; //Field str:Ljava/lang/String;
   63:  invokevirtual   #13; //Method java/lang/StringBuilder.append:(Ljava/lang
/String;)Ljava/lang/StringBuilder; //调用方法
   66:  invokevirtual   #15; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String; //调用方法
   69:  invokevirtual   #16; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V //调用方法
   72:  return
  LineNumberTable:
   line 20: 0
   line 21: 27
   line 22: 35
   line 23: 43
   line 24: 72

public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=1, Args_size=1
   0:   new     #19; //class A
   3:   dup
   4:   invokespecial   #20; //Method A."<init>":()V
   7:   iconst_2
   8:   invokevirtual   #21; //Method A.t:(I)V
   11:  return
  LineNumberTable:
   line 26: 0
   line 28: 11

static {};
  Code:
   Stack=1, Locals=0, Args_size=0
   0:   ldc     #12; //String min
   2:   putstatic       #8; //Field str:Ljava/lang/String;
   5:   ldc     #22; //String min2
   7:   putstatic       #14; //Field str2:Ljava/lang/String;
   10:  return
  LineNumberTable:
   line 15: 0
   line 16: 5

}

  通过字节码信息我们可以发现

system.out.print("min"+str2);Stringbuilder.append(String).append(I)toString;常量池一个对象2个对象

   0:   getstatic       #9; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   new     #10; //class java/lang/StringBuilder//StringBuilder对象
   6:   dup
   7:   invokespecial   #11; //Method java/lang/StringBuilder."<init>":()V
   10:  ldc     #12; //String min
   12:  invokevirtual   #13; //Method java/lang/StringBuilder.append:(Ljava/lang
/String;)Ljava/lang/StringBuilder;
   15:  getstatic       #14; //Field str2:Ljava/lang/String;
   18:  invokevirtual   #13; //Method java/lang/StringBuilder.append:(Ljava/lang
/String;)Ljava/lang/StringBuilder;
   21:  invokevirtual   #15; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;//调用stringbuilder.toString()方法。产生对象
   24:  invokevirtual   #16; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V




 System.out.println(str0+str);

字符串拼接。。。。结果同上

System.out.println("t--"+str3);

由于str3是final修饰的在编译期间就在常量池中了 t--minmin2

const #17 = String      #61;    //  t--minmin2

System.out.println(str4+str3);

由于str4.str3都是final编译常量所以同上

const #62 = Asciz       min3minmin2;

 System.out.println(“你好”+“吗”);

由于编译期间(“你好”+“吗”);已经在String常量池中了。同上

const #19 = String      #64;    //  你好吗

由于时间问题。写的比较毛糙。先写到这了。。下午还要上班。。先小睡会。。。。。下次在写

猜你喜欢

转载自m635674608.iteye.com/blog/1276677