关于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; // 你好吗
由于时间问题。写的比较毛糙。先写到这了。。下午还要上班。。先小睡会。。。。。下次在写