经典面试题1-java中String字符串常量池
题目:写出以下程序的输出结果(环境,jdk1.8)
public static void main(String[] args) {
String s1 = new StringBuilder("ja").append("va").toString();
String intern1 = s1.intern();
System.out.println(s1 == intern1);
String s2 = new StringBuilder("bei").append("jing").toString();
String intern2 = s2.intern();
System.out.println(s2 == intern2);
String s3 = new StringBuilder("1.8.0").append("_231").toString();
String intern3 = s3.intern();
System.out.println(s3 == intern3);
System.out.println("----------------------------------------");
String s4 = new String("hello") + new String("hello");
String s5 = "hellohello";
String intern4 = s4.intern();
System.out.println(s4 == s5);
System.out.println(s4 == intern4);
System.out.println(s5 == intern4);
String s6 = new String("hi") + new String("hi");
String intern6 = s6.intern();
String s7 = "hihi";
System.out.println(s6 == intern6);
System.out.println(s6 == s7);
System.out.println(intern6 == s7);
System.out.println("----------------------------------------");
String s8 = "ni" + "hao" + "ni";
String s9 = new String("ni") + new String("haoni");
String intern9 = s9.intern();
System.out.println(s9 == intern9);
}
解析
环境是jdk1.8!!!字符串入常量池的规则
1、第一次以字面字符串(一个或多个字面字符串拼接)形式出现,直接进入常量池
例如:
String s5 = “hellohello”;
String s8 = “ni” + “hao” + “ni”;
注:s8会在编译时常量折叠,编译器会优化成String s8 = “nihaoni”;2、常量池中没有,堆(一般的堆的概念)中有,用intern()方法加入到常量池中,会直接在常量池中引用该堆中字符串的地址(这点jdk1.6和jdk1.7(1.8)是不同的,jdk1.6相当于是常量池中第一次出现了这个字符串,不与堆中的关联)
注:
intern()方法返回的是常量池中那个字符串的地址,常量池中之前如果存在,则返回的就是存在的那个字符串的地址。
3、常量池中已经有了,再次以字面字符串出现或使用intern()方法出现时,都是引用的常量池中已经有的地址
注:
常量池中的字符串(jdk1.7(1.8))会存在几种情况:1、与堆中某个字符串地址关联,2、不与堆中字符串地址关联
结果
false:s1表示的字符串是java,但是java这个字符串在常量池不是第一次出现,系统加载的时候加载了一些字符串,所以intern1的地址是之前存在的java字符串的地址,而不是s1的地址
true:s2表示的字符串是beijing,在常量池第一次出现,所以intern2引用的是s2的地址
false:与第一个相同,jdk版本是1.8.0_231,这个字符串也在常量池存在了
----------------------------------------
false:s4在堆,s5在常量池,s5表示的字符串是第一次在常量池出现
false:intern4引用的是s5的地址,不是s4的地址
true:intern4引用的是s5的地址
true:s6在堆,intern6在常量池,intern6表示的字符串是第一次在常量池出现,引用的是s6的地址
true:s7表示的字符串不是第一次在常量池出现,引用之前出现的地址(intern6的地址),也就是s6的地址
true:s6、intern6、s7用的都是s6的地址
----------------------------------------
false:intern9引用的是s8的地址,不是s9的,与第一个是相同的场景
补充
“java”字符串第一次出现的地方:sun.misc.Version
package sun.misc;
import java.io.PrintStream;
public class Version {
private static final String launcher_name = "java";
private static final String java_version = "1.8.0_231";
private static final String java_runtime_name = "Java(TM) SE Runtime Environment";
private static final String java_profile_name = "";
private static final String java_runtime_version = "1.8.0_231-b11";
private static boolean versionsInitialized;
private static int jvm_major_version;
private static int jvm_minor_version;
private static int jvm_micro_version;
private static int jvm_update_version;
private static int jvm_build_number;
private static String jvm_special_version;
private static int jdk_major_version;
private static int jdk_minor_version;
private static int jdk_micro_version;
private static int jdk_update_version;
private static int jdk_build_number;
private static String jdk_special_version;
private static boolean jvmVersionInfoAvailable;
...
}
参考
1、https://www.cnblogs.com/tongkey/p/8587060.html
2、《深入理解Java虚拟机》(还没看过)