JAVA-基础知识-String,Stringbuffer,StringBuilder,字符串常量池

JAVA-基础知识-String,Stringbuffer,StringBuilder

  • 概述
    String 不可修改
    StringBuffer 可修改 线程安全
    StringBuilder 可修改 线程不安全

  • 三者之间的继承结构
    在这里插入图片描述

  • String
    String 对象一旦创建,其值是不能修改的,如果要修改,会重新开辟内存空间来存储修改之后的对象,即修改了 String 的引用。因为 String 的底层是用数组来存值的,数组长度不可改变这一特性导致了上述问题。
    这有张图可以很直观的看出来
    在这里插入图片描述

  • StringBuffer
    StringBuffer就是为了解决大量拼接字符串时产生很多中间对象问题而提供的一个类,它的本质是一个线程安全的可修改的字符序列,把所有修改数据的方法都加上了synchronized。但是保证了线程安全是需要性能的代价的。

  • StringBuilder
    StringBuilder与StringBuffer最大的区别在于线程安全,而StringBuilder没有实现同步,线程不安全,所以在多线程的环境下不能使用,但由于没有考虑同步的情况,他的开销要比StringBuffer小,所以在不需要考虑线程安全的环境下(e.g.单线程系统),追求效率的话可以使用StringBuilder。

  • 字符串常量池
    java为避免在一个系统中产生大量的String对象,引入字符串常量池。
    在创建一个字符串的时候,首先会检查池中是否有值相同的字符串对象,如果有直接返回引用,不会创建字符串对象;如果没有将新创建的对象放入池中。
    但是,通过new方法创建的String对象是直接放入堆中创建新对象,不会放入、引用池。
    以上原则只适用于直接给String引用对象赋值的情况。

    • String s1 = new String(“a1”); //不检查字符串常量池的
    • String s2 = “b1”; //检查字符串常量池的
  • 判断是否为同一个引用对象

public static void main(String[] args) {
       String s1 = "hello";
       String s2 = "hello";
       String s3 = "he" + "llo";
       String s4 = "hel" + new String("lo");
       String s5 = new String("hello");
       String s6 = s5.intern();
       String s7 = "h";
       String s8 = "ello";
       String s9 = s7 + s8;
       System.out.println(s1==s2);//true
       System.out.println(s1==s3);//true
       System.out.println(s1==s4);//false
       System.out.println(s1==s9);//false
       System.out.println(s4==s5);//false
       System.out.println(s1==s6);//true
       System.out.println(s1==s9);//false
}

s1,s2,s3均为直接引用常量池对象。其中s3在编译后就已经将后面两个字符串合并了,反编译后String s3 = “hello”;
s4:创建了两个对象,其中“hel”在常量池中,“lo”在堆中,本质上是两个对象相加,不会被编译器优化,相加结果在堆中。与s1不一致
s5:new新创建的字符串也在堆中,与s4不同,但在intern之后会被放入常量池中(如果有的话返回引用,没有则先创建再返回引用)
s9:两个变量相加的结果在堆中

  String s = new String("1");
  
  s.intern();
    
  String s2 = "1";
    
  System.out.println(s == s2);
    
  String s3 = new String("1") + new String("1");
  
  s3.intern();
  
  String s4 = "11";
    
  System.out.println(s3 == s4);

在这里插入图片描述

intern方法还是会先去查询常量池中是否有已经存在,如果存在,则返回常量池中的引用,这一点与之前没有区别,区别在于,如果在常量池找不到对应的字符串,则不会再将字符串拷贝到常量池,而只是在常量池中生成一个对原字符串的引用。
那么其他字符串在常量池找值时就会返回另一个堆中对象的地址。


版权声明:本文为wilbur_xieyj原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。