不可变字符串String和可变字符串StringBuffer和StringBuilder。

前言:

学习并且区分可变字符串何不可变字符串。

区分:

当字符串进行拼接等修改操作时,不可变字符串会创建新的字符串对象,而可变字符串不会创建新的对象。

String StringBuffer StringBuilder
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间 StringBuffer是可变类,和线程安全的字符串操作类,他的方法支持线程同步,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量 ,默认16 可变类,速度更快
不可变 可变 可变
线程安全 线程安全
多线程操作字符串 单线程操作字符串

字符串长度和字符串缓冲区容量的区别:

字符串长度:

字符串长度是目前在字符串缓冲区所包含的字符串长度,通过length()获得。

字符串缓冲区容量:

是指缓冲区所能承受的最大的字符串数,通过capacity()获得。当所容纳的字符超过这个个数的时候,缓冲区会自动扩容,但是牺牲了性能。

Java String类:

String的定义:

public final class String {
    private final char value[];
}

从 String 类是一个 final 类,它不可被继承,并且内部通过一个字符数组表示该字符串的内容,且一旦创建后,该字符串内容是不可变的,它的 equals 方法就是通过比较字符数组的内容是否相等来判断字符串对象是否相等
关于String对象创建的内存问题可以参考:https://blog.csdn.net/Mypromise_TFS/article/details/81504137

简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,这样不仅效率低下,而且大量浪费有限的内存空间,所以经常改变内容的字符串最好不要用 String 。因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

我们来看一下这张对String操作时内存变化的图:

image.png

我们可以看到,初始String值为“hello”,然后在这个字符串后面加上新的字符串“world”,这个过程是需要重新在栈堆内存中开辟内存空间的,最终得到了“hello world”字符串也相应的需要开辟内存空间,这样短短的两个字符串,却需要开辟三次内存空间,不得不说这是对内存空间的极大浪费。为了应对经常性的字符串相关的操作,就需要使用Java提供的其他两个操作字符串的类——StringBuffer类和StringBuild类来对此种变化字符串进行处理。
详细可以参考:https://www.jianshu.com/p/6fb953c9e9a5

注意:

String s = "abc" 方式创建的对象,存储在字符串常量池中,在创建字符串对象之前,会先在常量池中检查是否存在 abc 对象。如果存在,则直接返回常量池中 abc对象的引用,不存在会创建该对象,并将该对象的引用返回给对象 s。

以 HotSpot 虚拟机为例,在 jdk1.8 之前,字符串常量池在方法区中,为了减小方法区内存溢出的风险,在 jdk1.8 之后就把字符串常量池转移到 java 堆中了。

String s = new String("abc") 这种方式,实际上 abc 本身就是字符串池中的一个对象,在运行 new String() 时,把字符串常量池中的字符串 abc 复制到堆中,因此该方式不仅会在堆中,还会在常量池中创建 abc 字符串对象。 最后把 java 堆中对象的引用返回给 s。
参考:https://blog.csdn.net/codejas/article/details/81911802

StringBuffer 和 StringBuilder 类:

当对字符串进行修改的时候,特别是字符串对象经常改变的情况下,需要使用 StringBuffer 和 StringBuilder 类。

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。


image.png

初始化:

String s1 = null;   

       String s2 = "abc";   

       StringBuffer s3 = null; //结果警告:Null pointer access: The variable result can only be null at this location

       StringBuffer s4 = new StringBuffer();//StringBuffer对象是一个空的对象

       StringBuffer s5 = new StringBuffer("abc");//创建带有内容的StringBuffer对象,对象的内容就是字符串”
       System.out.println(s1);
       System.out.println(s2);
       System.out.println(s3);
       System.out.println(s4);
       System.out.println(s5);

原文显示s3的定义会报错,但是我试了没啥问题。

详细参考:https://blog.csdn.net/itchuxuezhe_yang/article/details/89966303

埋一个伏笔,线程安全日后更新。

你可能感兴趣的:(不可变字符串String和可变字符串StringBuffer和StringBuilder。)