public final class String
implements java.io.Serializable, Comparable, CharSequence {}
final修饰,不可变。String设计为不可变类主要考虑到:效率和安全。
效率:缓存hashcode,String不可变,所以hashcode不变,这样缓存才有意义,不必重新计算。
安全:String常被作为网络连接,文件操作等参数类型,倘若可改变,会出现意想不到的结果。
public static void main(String[] args) {
String str1 = "HelloFlyapi";
String str2 = "HelloFlyapi";
String str3 = new String("HelloFlyapi");
String str4 = "Hello";
String str5 = "Flyapi";
String str6 = "Hello" + "Flyapi";
String str7 = str4 + str5;
System.out.println("str1 == str2 result: " + (str1 == str2));
System.out.println("str1 == str3 result: " + (str1 == str3));
System.out.println("str1 == str6 result: " + (str1 == str6));
System.out.println("str1 == str7 result: " + (str1 == str7));
System.out.println("str1 == str7.intern() result: " + (str1 == str7.intern()));
System.out.println("str3 == str3.intern() result: " + (str3 == str3.intern()));
}
要理解String,那么要了解JVM内存中的栈(stack)、堆(heap)和方法区。简要图如下:
String str1 = "HelloFlyapi";
String str2 = "HelloFlyapi";
System.out.println(str1 == str2); // true
当执行第一句时,JVM会先去常量池中查找是否存在HelloFlyapi,当存在时直接返回常量池里的引用;当不存在时,会在字符创常量池中创建一个对象并返回引用。
当执行第二句时,同样的道理,由于第一句已经在常量池中创建了,所以直接返回上句创建的对象的引用。
String str1 = "HelloFlyapi";
String str3 = new String("HelloFlyapi");
System.out.println(str1 == str3); // false
执行第一句,同上第一句。
执行第二句时,会在堆(heap)中创建一个对象,当字符创常量池中没有‘HelloFlyapi’时,会在常量池中也创建一个对象;当常量池中已经存在了,就不会创建新的了。
String str1 = "HelloFlyapi";
String str6 = "Hello" + "Flyapi";
System.out.println(str1 == str6); // true
由于”Hello”和”Flyapi”都是常量,编译时,第二句会被自动编译为‘String str6 = “HelloFlyapi”;
String str1 = "HelloFlyapi";
String str4 = "Hello";
String str5 = "Flyapi";
String str7 = str4 + str5;
System.out.println(str1 == str7); // false
其中前三句变量存储的是常量池中的引用地址。
第四句执行时,JVM会在堆(heap)中创建一个以str4为基础的一个StringBuilder对象,然后调用StringBuilder的append()方法完成与str5的合并,之后会调用toString()方法在堆(heap)中创建一个String对象,并把这个String对象的引用赋给str7。
String str1 = "HelloFlyapi";//在常量池中创建
String str2 = "HelloFlyapi";//在常量池中创建
String str3 = new String("HelloFlyapi");//在堆上创建
String str4 = "Hello";
String str5 = "Flyapi";
String str7 = str4 + str5;//返回常量池中常量HelloFlyapi
System.out.println("str1 == str7.intern() result: " + (str1 == str7.intern()));//true
System.out.println("str3 == str3.intern() result: " + (str3 == str3.intern()));//false
String.intern()分析:
判断这个常量是否存在于常量池。
如果存在
判断存在内容是引用还是常量,
如果是引用,
返回引用地址指向堆空间对象,
如果是常量,
直接返回常量池常量
如果不存在,
将当前对象引用复制到常量池,并且返回的是当前对象的引用
具体分析可参考
https://blog.csdn.net/u013366617/article/details/83618361
文章摘自
https://zhuanlan.zhihu.com/p/60643031