浅谈对String的了解

String定义

 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的了解_第1张图片

第一个

 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

你可能感兴趣的:(Java)