1.==比较问题
String a = "hello";
String b = "hello";
String c = "he" + "llo";
String d = "he" + new String("llo");
a == b //1
a == c //2
a == d //3
首先公布答案,式子1返回true,式子2返回true,式子3返回false
式子1很好理解,由于存在字面量池,在用字面量赋值时,如果池中已经有了相同的字面量,就不会开辟新的空间,而是直接指向池中该字面量
式子2在字面量池中又创建了”he”和”llo”两个字面量,但由于编译器的存在,在编译期便可以做到字面量的连接工作,所以”he”+”llo”仍然可以看作”hello”
式子3中的new String(“llo”)在编译期不会被编译器识别,只能在运行期才能在堆中存放这个对象,而运行期的字符串连接过程是这样的:new StringBuilder().append(a).append(b).toString(),返回的是一个新的对象,所以会返回false
2.String的不可变性
String的不可变性体现在一旦new了一个新的String对象,就不能改变对象的状态,只能让这个变量指向新的对象。这个特性带来的好处有:
1.线程安全
因为String对象不可变,所以可以放心的让多个线程访问同一个String对象
2.字面量池
正是因为String的不可变性,才会有字面量池的存在。否则,字面量池中的对象就会被随意更改,那么所有引用了这个对象的变量值也会被一同更改
3.String作为形参的问题
看下面这个例子:
public static void change(String a){
a = a + "123";
}
public static void main(String[] args){
String a = "hello";
change(a);
System.out.println(a); //hello or hello123 ?
}
正确答案是hello,也就是对String形参的更改不会影响到实参
有人问String又不是基本类型,它不应该是按引用传递的吗?
我们首先要明白这一点,虽然按引用传递时,我们可以改变实参,但我们无法让这个引用指向新的实参,就比如:
public void change(MyClass a){
a = new MyClass();
}
这种操作是无效的
由于String是不可变的 ,所以任何改变String的操作实际上都是new了一个新的对象,所以我们无法对这个引用指向的原实参造成任何影响,这样看上去String就像按值传递一样