String-学习笔记(3)
String对象的不变性说明
代码:
String s = "abcd";
String s2 = s;
String-Immutability-2.jpeg
代码:
s = s.concat("ef");字符串拼接
string-immutability-650x279.jpeg
一旦一个string对象在堆中被创建出来,它就无法被修改,无论是什么方法都返回一个新的字符串对象(如果需要不断修改字符串,那么应该使用StringBulider或者StringBuffer,否则每次拼接都会创建新的对象,最后对导致创建出很多无用对象)
常量池中的String
字符串常量池是方法区中一部分区域,当一个字符串常量被创建的时候,会先到常量池中找,如果找到则返回该字符串的引用。
代码:
String string1 = "abcd";
String string2 = "abcd";
QQ20160302-3.png
所以,如果字符串可变的话,string2的修改将会直接影响string1
缓存Hashcode
java中经常使用的哈希码,例如在HashMap中,字符串作为Key值时,字符串的不变性可以保证其hashcode永远保持一致,在使用一个字符串的hashcode的时候不用每次重新计算一次。
安全性
String被广泛的使用在其他Java类中充当参数。比如网络连接、打开文件等操作。如果字符串可变,那么类似操作可能导致安全问题。可变的字符串也可能导致反射的安全问题,因为反射调用的参数也是字符串。
如何创建字符串
在Java中,有两种方式可以创建字符串:
String x = "abc";
String y = new String("abc");
双引号创建:
String a = "abcd";
String b = "abcd";
System.out.println("a == b : "+(a == b)); // true
System.out.println("a.equals(b) : "+(a.equals(b))); // true
因为a与b都是"abcd",所以都返回字符串常量池的地址
构造函数创建:
String c = new String("abcd");
String d = new String("abcd");
System.out.println("c == d : "+(c == d)); // false
System.out.println("c.equals(d) : "+(c.equals(d))); // true
c与d的地址不同是因为他们分别指向堆中的不同对象
运行时字符串驻留:
String c = new String("abcd").intern();
String d = new String("abcd").intern();
System.out.println("c == d : "+(c == d)); // true
System.out.println("c.equals(d) : "+(c.equals(d))); // true
上面的代码由于"abcd"在类加载时就已经从.class文件中获取到放入常量池中,所以上面的c和d读取的都是类加载时的地址(在String-学习笔记(2)中有提过),所以它们相等,并且这样直接返回引用会省去很多new操作的耗时
所以,所以只使用一个字符串,可以使用双引号方式,如果需要在堆中创建一个对象可以使用构造函数的方式
switch对字符串的支持
java7之后switch开始支持string,其实switch对string的支持最终也是转为int简单类型进行比较
代码:
String str = "Hard";
switch (str) {
case "Hard":
System.out.println("Hard");
break;
case "WJJ":
System.out.println("WJJ");
break;
default:
break;
}
反编译后:
String str;
String string = str = "Hard";
int n = -1;
switch (string.hashCode()) {
case 2241803: {
if (!string.equals("Hard")) break;
n = 0;
break;
}
case 85975: {
if (!string.equals("WJJ")) break;
n = 1;
}
}
switch (n) {
case 0: {
System.out.println("Hard");
break;
}
case 1: {
System.out.println("WJJ");
break;
}
}
可以看出switch支持string其实也就是通过hashcode+equals方法来实现的,进行hashcode之后还要进行equals时因为由于hash冲突hash值相同只是第一步,equals相等才表示两个String值相等,另外,如果是两个字面量进行equals的话,比较是非常快速的,因为都是取常量池中的引用进行比较,所以switch中只支持整型int,能支持string只是为了方便程序员,编译后还是通过整型比较