面试系列(2)Java String

作者: kevenZheng | 来源:发表于2019-01-04 18:06 被阅读20次

1、常量池

Java 被编译成 class 文件时,会生成一个常量池(Constant pool)的数据结构,用于保存字面常量和符号引用(类名、方法名、接口名和字段名等)。常量池的内存在 Java 堆上进行分配,意味着常量池不受固定大小的限制。

2、字符串初始化

字符串初始化的方式有两种:字面常量、String 对象

(1)如下一段代码:

String a = "java";
String b = "java";
String c = "ja" + "va";
System.out.println("一致性"+(a==b));
System.out.println("一致性"+(a==c));
System.out.println("一致性"+(b==c));

输出结果是:

image

我们通过 javap -c 命令分析一下字节码指令的实现:

image

通过上图可以看出,ldc 指令将 int、float、String 等类型的常量值从常量池中推送到栈顶,所以 a、b 都指向常量池中 "java" 字符串,同时也可以发现 c 也指向常量池中 "java" 字符串,那是因为在编译期间,表达式 "ja"+"va" 已经将结果值 "java" 直接赋值给 c

(2)如下一段代码:

String a = "java";
String c = new String("java");
System.out.println((a==c));

输出结果为:

image

我们通过 javap -c 命令分析一下字节码指令的实现:

image

通过上图可以分析出,a 指向常量池中的 "java" 字符串,c 指向 Java 堆中新建的 String 对象,而该对象的 char 数组则指向常量池中的 "java" 字符串,所以得出结论,a != c

(3)如下一段代码:

String a = "ja";
String b = "va";
String c = a + b;
String d = "java";
System.out.println(c == d);

输出结果:

image

我们通过 javap -c 命令分析一下字节码指令的实现:

image

可以看到会创建一个 StringBuilder 对象,然后将 a、b 拼接起来,然后通过 toString 方法产生一个 String 对象 c,而 d 是直接指向常量池中的字符串 "java",所以得出 c != d

(4)但如果是如下代码:

final String a = "ja";
final String b = "va";
String c = a + b;
String d = "java";
System.out.println(c == d);

则能输出 true

我们通过 javap -c 命令分析一下字节码指令的实现:

image

通过上图可以看出,用 final 修饰后,在编译期间,就已经将 a 和 b 拼接好赋值给 c 了,然后 c 和 d 同时指向常量池中字符串 "java",所以得出的结论是 c == d

3、String、StringBuffer和StringBuilder的区别

三者本质上都是字符数组

(1)String 是不可变的对象,因此每次改变 String 的时候,都会产生一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串不要使用 String,如果要操作少量的数据,则可以使用 String

(2)单线程操作大量数据,使用 StringBuilder,因为不用保证线程同步,所以速度更快

(3)多线程操作大量数据,使用 StringBuffer,因为需要考虑线程同步,所以速度更慢一些

相关文章

网友评论

    本文标题:面试系列(2)Java String

    本文链接:https://www.haomeiwen.com/subject/ykpkrqtx.html