用好字符串,提防陷阱

来源:互联网 发布:ipad看电视剧软件 编辑:程序博客网 时间:2024/04/30 05:51

最基础的知识总是最容易忘记的,所以在回顾一下字符串吧,加深记忆


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 = "字符串";//输出trueSystem.out.println(s1 == s2);}}


所以,由于s1 和 s2 都是指向字符串变量中的“字符串”,所以他们的物理地址相等,所以 == 为true


2、字符串连接表达式可以在编译是确定下来,那么JVM会在编译是计算字符串变量的值,并让它指向字符串池中对应的字符串

public class Test2{public static void main(String[] args){String s1 = "字符串10";String s2 = "字" + "符串" + 10;//输出trueSystem.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;//两个都输出falseSystem.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;//输出trueSystem.out.println(s1 == s2);}}

4、不可变长字符串

String s = "字符串" + "的长度" + "3";

看一下这段代码产生几个变量?

实际上,只有一个,因为JVM会在编译是就计算出s的值为“字符串的长度为3”,所以将该字符串存放在字符串池中,并让s指向它


那在看一下代码

public class Test5{public static void main(String[] args){String s = "字符串";    // 1System.out.println(System.identityHashCode(s));s = s + "的长度为:";    // 2System.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







0 0