//String的类声明以及value字段代码: public final class String implements java.io.Serializable, Comparable<String>, CharSequence { private final char value[]; //字符数组存储String的内容 /** Cache the hash code for the string */ private int hash; // Default to 0 }
不可变的验证分析:
public class Immutable { public static String upcase(String s) { return s.toUpperCase(); } public static void main(String[] args) { String q = "howdy"; System.out.println(q); // howdy String qq = upcase(q); System.out.println(qq); // HOWDY System.out.println(q); // howdy } } /* 输出: howdy HOWDY howdy *///:~
延伸结论:
String对象作为方法的参数时,都会复制一份引用,参数传递是引用的拷贝
1. 可以缓存 hash 值
String的hash值经常被使用,例如String用做HashMap的key。不可变的特性可以使得hash值也不可变,因此只需要进行一次计算。
2. String Pool 的需要
如果一个String对象已经被创建过了,那么就会从 String Pool 中取得引用。只有String是不可变的,才可能使用 String Pool。
3. 线程安全
String不可变性天生具备线程安全,可以在多个线程中安全地使用。
String使用“+”表示字符串拼接
先说结论:
验证:
public class StringBuilderTest { public static void main(String[] args) { String s1 = "ABC"; String s2 = "123"; String result = s1+s2; System.out.println(result); } }
编译并查看字节码:javap -verbose StringBuilderTest.class
执行过程:
调用了2次append()方法,最后调用StringBuilder.toString()返回最终结果
为什么StringBuilder要比+高效?
源码追溯:
//StringBuilder.append() @Override public StringBuilder append(char c) { super.append(c); return this; } // 父类 AbstractStringBuilder.append() @Override public AbstractStringBuilder append(char c) { ensureCapacityInternal(count + 1); value[count++] = c; return this; } //AbstractStringBuilder value 字段 abstract class AbstractStringBuilder implements Appendable, CharSequence { //The value is used for character storage. char[] value; // 没有声明为final,因此value可变 }
手动实现StringBuilder对象操作比编译器自行优化,更高效:
当你为一个类编写toString方法时,如果字符串操作比较简单,那就可以信赖编译器,它会为你合理地构造最终的字符串结果。但是,如果你要在toString0方法中使用循环,那么最好自己创建一个StringBuilder对象来实现。
可变性
线程安全
效率
一、引入字符串常量池
案例1:
String s1 = "win"; String s2 = "win"; System.out.println(s1==s2); //输出结果:true //引用 s1 s2 的值等于win在字符串常量池的地址值
结论:
引用 s1 s2 的值等于win在字符串常量池的地址值
分析字节码的执行过程:
案例2:
public class StringPool { public static void main(String[] args) { String s3 = new String("win"); String s4 = new String("win"); System.out.println(s3==s4);//false } }
结论:
通过new操作符创建的字符串对象不指向字符串池中的任何对象。
字节码分析:
综上:
public class StringPool { public static void main(String[] args) { String s1 = "win"; String s2 = "win"; String s3 = new String("win"); String s4 = new String("win"); System.out.println(s1==s2);//true System.out.println(s1==s3);//false System.out.println(s3==s4);//false } }
从这个表中可以看出,当需要改变字符串的内容时,String类的方法都会返回一个新的String对象。同时,如果内容没有发生改变,String的方法只是返回指向原对象的引用而已。这可以节约存储空间以及避免额外的开销。
以上就是Java基础类学习之String详解的详细内容,更多关于Java String类的资料请关注其它相关文章