一、新建了几个对象?
String str1 = "aaa"; //新建1个对象
String str2 = "bbb"; //新建1个对象
String str3 = "aaabbb"; //新建1个对象
String str4 = "aaa" + "bbb";//由于str3不会产生新的字符串对象
System.out.println(str3 == str4);//true
String str41 = str1 + "bbb";//会产生新的字符串对象,
System.out.println(str3 == str41);//false
String str42 = str1 + str2;//会产生新的字符串对象
System.out.println(str3 == str42);//false
String str5 = new String(Str3); //产生新的字符串对象
String str6 = new String("aaabbb");//产生新的字符串对象
String str4 = "aaa" + "bbb"
(如果没有前提str3) 只创建1个对象。由于常量字符串是在编译的时候就也被确定的,又因"aaa"和"bbb"都是常量,因此变量str的值在编译时就可以确定。
String str41 = str1 + "bbb";
//会产生新的字符串对象。 因为 “+ ”操作实际上是新建一个StringBuilder()并调用append()方法,生成了一个新对象。
二、String.intern()
String.intern()
是一个本地方法,他的作用是如果字符串常量池中已经包含一个等于此String对象的字符串,则返回此String对象的引用;否则把此String对象的字符串拷贝到字符串常量池。
2.1 JDK不同版本中的intern()方法
JDK 6
JDK 7
三、字符串常量池在运行时数据区的位置
JDK 6以及以下,字符串常量池在方法区中,可以通过 -XX:PermSize
和 -XX:MaxPermSize
去设置方法区(永久代);
JDK 7或者更高版本的JDK ,字符串常量池在堆中。
如下代码,结果是什么?分析下,
public static void main(String[] args) {
String str1 = new StringBuilder("计算").append("机").toString();
System.out.println(str1.intern() == str1);
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2);
}
#JDK 6 运行结果是:
false
false
#JDK 7 运行结果是:
true
false
JDK 6及以下
中intern()方法会把字符串实例复制到永久代的字符串常量池中。而 JDK 7及以上版本
中,因为字符串常量池在堆中,所以intern()方法仅仅把字符串实例引用放入字符串常量池中。
所以 JDK 6 执行 str1.intern() == str1 为 false , str1.intern() 返回的是永久代字符串常量池里面的对象引用,而str1返回的是堆中对象的引用。
JDK 7 执行 str1.intern() 返回的是字符串实例引用,和new StringBuilder(“计算机”)对象引用是同一个。
而 str2 的结果false, 是因为在执行
new StringBuilder("ja").append("va").toString()
之前,就已经存在了,它是加载sun.misc.Version这个类的时候就进入常量池的。