最基础的知识总是最容易忘记的,所以在回顾一下字符串吧,加深记忆
1、定义字符串的两种最常见的形式
String s1 = new String("字符串"); (1)
String s2 = "字符串"; (2)
那这两种有什么区别呢
实际上,由(1)种首先JVM会查看一下字符串池中有没有"字符串"这个直接量,没有的话,就在字符串池创建相应的直接量对应的字符串对象,然后再由new String()构造器返回的字符串对象,所以他实际上创建2个字符串对象
而第(2)种则只是检查字符串池中有没有"字符串"这个直接量,没有的话,就在字符串池创建相应的直接量对应的字符串对象
所以,可见,直接量创建的方式要比new方式创建效率高(其他封装类型也有相识的情况)
public class Test1
{
public static void main(String[] args)
{
String s1 = "字符串";
String s2 = "字符串";
//输出true
System.out.println(s1 == s2);
}
}
2、字符串连接表达式可以在编译是确定下来,那么JVM会在编译是计算字符串变量的值,并让它指向字符串池中对应的字符串
public class Test2
{
public static void main(String[] args)
{
String s1 = "字符串10";
String s2 = "字" + "符串" + 10;
//输出true
System.out.println(s1 == s2);
}
}
由于s1 、s2 在编译阶段已经指向了同一个直接量,所以运行时 == 为true
3、字符连接要是涉及到方法、变量(不是宏替换 final)时,编译时无语确定他的实际值
public class Test3
{
public static void main(String[] args)
{
int len = 3;
String s1 = "字符串的长度:3";
String s2 = "字符串的长度"+"字符串".length();
String s3 = "字符串的长度:" + len;
//两个都输出false
System.out.println(s1 == s2);
System.out.println(s1 == s3);
}
}
由于编译时,无法确定s2、s3变量的值,所以 == 为false;
然而,当变量为宏替换时,在编译阶段就已经替换为相应的值,也就是值已经确定
public class Test4
{
public static void main(String[] args)
{
final int len = 3;
String s1 = "字符串的长度:3";
String s2 = "字符串的长度:" + len;
//输出true
System.out.println(s1 == s2);
}
}
4、不可变长字符串
String s = "字符串" + "的长度" + "3";
看一下这段代码产生几个变量?
实际上,只有一个,因为JVM会在编译是就计算出s的值为“字符串的长度为3”,所以将该字符串存放在字符串池中,并让s指向它
那在看一下代码
public class Test5
{
public static void main(String[] args)
{
String s = "字符串"; // 1
System.out.println(System.identityHashCode(s));
s = s + "的长度为:"; // 2
System.out.println(System.identityHashCode(s));
s = s + 3; //3
System.out.println(System.identityHashCode(s));
}
}
结果:
明明是同一个变量,为什么结果确实不相同的呢?
原来String字符串是不可变长的,也就是在第1句代码执行时,jvm将“字符串”直接量存入字符串迟,再将s指向它;在第2句执行时,jvm又生成“字符串的长度为”的直接量,再将s指向它,于是字符串池就有两个字符串变量了;第3句执行时字符串池就有三个变量了;
所以指向对象不同,hashcode肯定不同了,这种情况还要注意,因为在垃圾回收时,字符串池的变量不会被回收,很容易造成内存泄漏
所以,推荐使用StringBuffer、StringBuilder
两者的区别就是StringBuffer大部分方法是线程安全的,而效率也会低一点了
String由于不可变长,字符串改变时,指向变量改变,所以也是线程安全的了
public class Test6
{
public static void main(String[] args)
{
StringBuilder s = new StringBuilder("字符串");
System.out.println(System.identityHashCode(s));
s.append("的长度");
System.out.println(System.identityHashCode(s));
s.append(3);
System.out.println(System.identityHashCode(s));
s.replace(0, 1, "23");
System.out.println(s);
System.out.println(System.identityHashCode(s));
}
}
结果:
总结:
1、String是不可变长的,同时他的new出来的对象会产生两个对象
2、在字符串连接比交多的地方,建议使用StringBuffer、StringBuilder