一、String类的常见问题解析
1.1、new String(“hello”)创建了几个对象
不考虑其他因素,String b = new String("hello");
这行代码到底创建了几个对象?
情况一,创建了一个
对象:
String a = "hello";
// 下面这一行代码创建了一个对象
String b = new String("hello");
情况二,创建了两个
对象:
// 下面这一行代码创建了两个对象
String b = new String("hello");
String a = "hello";
所以,在以下代码片段
中,综合其他代码的情况下
,它可能是创建了一个,或者两个对象。如果不考虑其他代码
,就这样一行运行,那么它就是和第二种情况
一样,创建了两个对象
。
String b = new String("hello");
因为在new String对象的时候,如果它需要的字符串在常量池中有了,那么这个String对象的成员变量value[]
的值,就指向常量池中的对象,如果没有,就在常量池中新建一个字符串对象,然后再指向它,而String对象本身是在堆里的,下面进行详细的解释。
(1)创建了一个对象的情况(情况一)
"hello"
这个字符串,在创建对象之前,就在常量池
中已经存在了
:
(1)那么第一行代码String a = "hello";
就是在常量池中创建了值为"hello"
的对象,我们讨论的是第二行代码。
(1)在第二行代码String b = new String("hello");
是在堆
里面创建了一个对象,引用b
指向这个对象,而常量池中有值为"hello"
这个对象,然后引用b
指向的对象(new String("hello")
)的成员变量char
数组value[]
指向常量池值为"hello"
这个对象就行了,它就创建了一个对象new String("hello")
。
下面进行验证,我们将下面输出语句打上断点,方便进行查看:
在Debug模式下,可以看见变量a
和b
的成员变量char
数组value[]
的地址是一样的,即是同一个char
数组,代码String b = new String("hello");
并没有为它的成员变量value[]
创建新对象,而是指向了常量池中的值为hello
的对象,即它只创建了一个对象。因此我们上面的分析是正确的。
(2)创建了两个对象的情况(情况二)
"hello"
这个字符串,创建对象之前,在常量池
中不存在
:
(1)第一行代码String b = new String("hello");
是在堆
里面创建了一个对象,引用b
指向这个对象,然后发现常量池没有值为hello
的对象,于是进行创建,然后将这个String
对象成员变量char
数组value[]
,指向值为"hello"
这个对象,这里一行代码就创建了两个对象。
(2)然后第二行代码String a = "hello";
直接将引用指向常量池中,值为"hello"
的对象就行了。
下面进行验证,同样为了方便进行查看,我们打上断点,注意代码顺序调换了:
还是可以发现,变量a
和b
的成员变量char
数组value[]
的地址是一样的,即是同一个char
数组,在执行String b = new String("hello");
有为它的成员变量value[]
在常量池中创建新的对象,因为代码String a = "hello";
的对象是在常量池中,但它却没有指向新的对象,它的成员变量,和第一行代码执行创建的对象的成员变量value[]
的地址是一样的,即第一行代码执行的时候创建了两个对象。因此我们上面的分析是正确的。
注意:以上分析的时候,要知道String a = "hello";
创建的对象是在常量池中,String b = new String("hello");
创建的对象是在堆中。
1.2、判断各种字符串对象相等的情况
如下代码:
String s = "12";
String s1 = "34";
String s2 = s + s1;
String s3 = "1234";
String s4 = "12" + "34";
String s5 = s + "34";
String s6 = "12" + new String("34");
// 第一题
System.out.println(s2 == s3); // false
// 第二题
System.out.println(s2 == s4); // false
// 第三题
System.out.println(s3 == s4); // true
// 第四题
System.out.println(s3 == s5); // false
// 第五题
System.out.println(s2 == s5); // false
// 第六题
System.out.println(s3 == s6); // false
以上题目你是否做对了呢?
做题之前,我们先了解一下规则:
(1)、Sun规定String类型运算的时new了StringBuilder对象,然后用append()方法追加字符串,最终以StringBuilder的toString()方法返回,而它的toString()方法是直接new了一个String对象返回的,那么 == 去比较两个String对象的地址,肯定是不相等的。
(2)、像"a"+"a"
这种没有变量参与则在编译时就能确定,这种拼接会被优化,编译器直接帮你拼好,就不需要new的操作。
于是就上面这些题目很容易得出结果了,注意第一题和第六题,因为也有变量参与了运算,这种在编译期也是无法确定的,也会根据规则(1)运算。