javaSE-String,StringBuffer和StringBuilder

简介: javaSE-String,StringBuffer和StringBuilder

       对于String类

       1、String类对象内容的不可变性

       String类的对象的内容是不能被改变的。即String对象一旦被创建,其组成这个String类对象的字符数组(或者说是字符数列)是无法被修改的。String类里面的方法,例如subString,replace和trim方法,都是不能修改本身的字符串,只能创建改字符串对象的一个副本然后才对其进行相关操作并返回这个被操作后的副本。

       例如:

public class Main {
    public static void main(String[] args) {
        String str1 = "hello world!";
        str1.replace("l","L");
 
        String str2 = "  hello java!  ";
        str2.trim();
 
        System.out.println(str1);
        System.out.println(str2);
    }
}

运行结果如下:


efe2a7e13d0834caf27ec251776d136c_72da18172dd64a0299a9ed4b7a32eb4e.png

        创建两个字符串 str1 = "hello world!";  str2  =  "  hello java!  ";

然后对str1进行replace操作,对str2进行trim去除首尾空格操作,然后打印str1和str2操作,

从其结果可以看出来:String类里面的方法并不能修改String对象的内容。


      2、从源代码观察这种机制

       在idea里面查看源代码,如下:


       可以发现,其实String类的对象的字符存储是以 字符数组的形式存放的,并且这个数组被private关键字和final 关键字修饰,被final关键字修饰的变量就变成了常量,是无法被修改的,但是这并不是其根本原因,其根本所在是因为被final修饰的变量无法被其子类继承,和private修饰,这个value变量其实是一种引用,final修饰这个value表明,value所指向的对象的引用地址不能修改,但是可以修改value数组中的内容,例如,有如下代码:

public class Main {
    public static void main(String[] args) {
        final char[] arr = {'a','b','c'};
        arr = new char[]{'c','c','c'};
    }
}

        因为arr被final修饰,所以无法将arr 本身指向另外一个字符串数组对象。

结果如下:


public class Main {
    public static void main(String[] args) {
        final char[] arr = {'a','b','c'};
        for (int i = 0; i < arr.length; i++) {
            arr[i] = 'x';
        }
        System.out.println(arr);
    }
}

代码结果如下:

可以看到,其实arr的值,也就是value的值其实是可以被修改的

而实际上不能被修改的原因是:


       为什么String类的方法不会修改字符串本身?从源代码的层次看,以下是String类的一些方法:

substring();

public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }


replace();

public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */
 
            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }


       可以看出,他们最终都是return 返回一个new 关键字新建的字符串对象,而不是在原来的字符串的基础上进行修改。


      3、如何理解这种不可变机制?

        这种无法被修改的机制可以完美地体现出java语言的安全性。虽然字符串对象的内容无法被修改,但可以修改String 变量所指向的对象:

        上面我们所说,关于String类的一些方法都无法修改原字符串,而是新建一个副本,那么如果有一种要求,需要我们不断地去拼接字符串,那么就会存在一个问题,他会在连接的过程中,不断地创建字符串对象,而创建字符串对象是对性能有消耗的,运行效率非常低下,不推荐


       为了解决这个问题

       StringBuffer和StringBuilder前导:

       String对象一段创建就无法修改,但是如果想创建一个可变的字符串该怎么办?


       除了String类可以用来存储字符串,java提供了StringBuffer和StringBuilder类来存储,StringBuffffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作,在性能下,StringBuilder 的性能是要高于StringBuffer的。

       StringBuilder

       StringBuilder类也可以用来高效地处理字符串,尤其是在字符串连接的时候。因为StringBuilder是java的JDK 5.0版本新增的类,他是一个可变的字符序列:

        1、 声明

public class Main {
    public static void main(String[] args) {
        StringBuilder tem = new StringBuilder("hello world!");
        System.out.println(tem);
    }
}


        2、构造方法

       ①无参构造

无传入值,调用无参构造方法:


StringBuilder继承AbstractStringBuilder,AbstractStringBuilder中有属性:

char[ ] value;

int count;


构造StringBuilder对象前,先对父类AbstractStringBuilder进行构造方法:

最终生成一个StringBuilder类的实例对象,如下:


可以看出来,无参构造方法生成的StringBuilder实例对象的value字符数组默认大小为16.

       ② 传入字符串

调用构造方法StringBuilder,首先调用父类构造方法:


构造StringBuilder:value数组的长度为原字符串长度 + 16

然后追加append 字符串:


首先调用父类append方法:

将传入的str对象拷贝到value数组中:


最终数组的大小为  传入的字符串的长度 +  16,但是不能超过Integer.MAX_VALUE  - 8

       ③ 传入int 类型的值


创建一个长度为传入值大小的容量空字符数组char[ ] arr, 所对应的字符串为空字符串。

       假设传入int值为8,其结果如下:

       StringBuilder类中的方法

       这两个类大 部分功能是相同的,这里介绍 StringBuilder 常用的一些方法:


这里面很多方法都和String类的用法相类似,这里不再做过多的代码案例介绍。

       其中append方法就类似与 += 操作,但是StringBuilder的 += 和append不会新重新创建并返回一个对象,而是在原来的已经存在的字符数组中做修:


String类和StringBuilder类实例之间的转化

       1、String → StringBuilder

      使用构造方法:

String str = "hello world!";

StringBuilder stringBuilder = new StringBuilder(str);

      使用append方法:

String str = "hello world!";

StringBuilder stringBuilder = new StringBuilder();

stringBuilder.append(str);

        2、Stringbuilder → String

使用StringBuilder  的  toString()方法


StringBuilder stringBuilder = new StringBuilder("hello world!");

String str = stringBuilder.toString();


String,StringBuilder,StringBuffer比较

       1、String

       String是不可变的对象,一旦创建,无法修改其value数组的值,每次对String进行 += 或者与其他类型的数据连接的时候,都会新建一个对象,每次创建一个对象都有性能的消耗,频繁地拼接字符串对系统的性能会产生一定的的影响。


       2、StringBuffer

       StringBuffer是可变字符串,每次对字符串的修改都是对其对象本身操作,不会新建对象,再改变对象的引用。因此,在频繁的使用字符串拼接的场景下,建议使用StringBuffer,


       3、StringBuilder

       StringBuilder是java的JDK 5.0版本之后提供的类,它同StringBuffer类等价,只不过区别在于:StringBuffer是线程安全的,StringBuilder类是单线程,不提供同步,线程安全问题,会在后面的线程这一部分知识点中讲解。


面试题

下面这条语句一共创建了多少个对象:String s= "welcome'+"to"+360;

A. 1

B. 2

C. 3

D. 4

正确答案:A


解析:


       对于字符串常量的拼接,实在java编译器编译期间执行的,在编译期间对这三个字面量进行+操作,最终生成一个"welcometo360"字符串常量,然后编译器会在常量池中寻找是否有和这个

"welcometo360"内容相同的字符串,如果有,则直接让s指向这个已经在常量池存在的字符串,如果没有,则重新在常量池中生成一个字符串对象。这就是java的优化机制。


       所以这题题意并不算严谨。而对于字符串实例的拼接,实在java运行期间执行的,会在堆中重新生成一个对象。

目录
相关文章
|
3月前
|
安全 Java API
【Java字符串操作秘籍】StringBuffer与StringBuilder的终极对决!
【8月更文挑战第25天】在Java中处理字符串时,经常需要修改字符串,但由于`String`对象的不可变性,频繁修改会导致内存浪费和性能下降。为此,Java提供了`StringBuffer`和`StringBuilder`两个类来操作可变字符串序列。`StringBuffer`是线程安全的,适用于多线程环境,但性能略低;`StringBuilder`非线程安全,但在单线程环境中性能更优。两者基本用法相似,通过`append`等方法构建和修改字符串。
64 1
|
2月前
|
安全 Java
String、StringBuffer、StringBuilder的区别
这篇文章讨论了Java中String、StringBuffer和StringBuilder的区别。String是不可变的,每次操作都会产生新的对象,效率低且浪费内存。StringBuilder可以在原字符串基础上进行操作,不开辟额外内存,弥补了String的缺陷。StringBuffer和StringBuilder类似,但StringBuffer的方法是线程安全的。文章还列举了StringBuffer的常用方法,并提供了使用示例代码。最后总结了这三者的主要区别。
String、StringBuffer、StringBuilder的区别
|
1月前
|
canal 安全 索引
(StringBuffer和StringBuilder)以及回文串,字符串经典习题
(StringBuffer和StringBuilder)以及回文串,字符串经典习题
33 5
|
24天前
|
存储 安全 Java
String、StringBuffer 和 StringBuilder 的区别
【10月更文挑战第21天】String、StringBuffer 和 StringBuilder 都有各自的特点和适用场景。了解它们之间的区别,可以帮助我们在编程中更合理地选择和使用这些类,从而提高程序的性能和质量。还可以结合具体的代码示例和实际应用场景,进一步深入分析它们的性能差异和使用技巧,使对它们的理解更加全面和深入。
14 0
|
2月前
|
安全 Java
Java StringBuffer 和 StringBuilder 类详解
在 Java 中,`StringBuffer` 和 `StringBuilder` 用于操作可变字符串,支持拼接、插入、删除等功能。两者的主要区别在于线程安全性和性能:`StringBuffer` 线程安全但较慢,适用于多线程环境;`StringBuilder` 非线程安全但更快,适合单线程环境。选择合适的类取决于具体的应用场景和性能需求。通常,在不需要线程安全的情况下,推荐使用 `StringBuilder` 以获得更好的性能。
|
3月前
|
Java
【Java基础面试二十六】、说一说String和StringBuffer有什么区别
这篇文章区分了Java中的String和StringBuffer类:String是不可变类,一旦创建字符序列就不能改变;而StringBuffer代表可变的字符串,可以通过其方法修改字符序列,最终可以通过`toString()`方法转换为String对象。
【Java基础面试二十六】、说一说String和StringBuffer有什么区别
|
3月前
|
安全 Java API
Java系类 之 String、StringBuffer和StringBuilder类的区别
这篇文章讨论了Java中`String`、`StringBuffer`和`StringBuilder`三个类的区别,其中`String`是不可变的,而`StringBuffer`是线程安全的可变字符串类,`StringBuilder`是非线程安全的可变字符串类,通常在单线程环境下性能更优。
Java系类 之 String、StringBuffer和StringBuilder类的区别
|
3月前
|
安全 Java
【Java基础面试二十七】、说一说StringBuffer和StringBuilder有什么区别
这篇文章介绍了Java中StringBuffer和StringBuilder的区别:StringBuffer是线程安全的,而StringBuilder是非线程安全的,因此在单线程环境下优先推荐使用StringBuilder以获得更好的性能。
|
3月前
|
安全
String,Stringbuffer,StringBuilder的区别
【8月更文挑战第16天】String,Stringbuffer,StringBuilder的区别
35 2
|
3月前
|
API C# 开发者
WPF图形绘制大师指南:GDI+与Direct2D完美融合,带你玩转高性能图形处理秘籍!
【8月更文挑战第31天】GDI+与Direct2D的结合为WPF图形绘制提供了强大的工具集。通过合理地使用这两种技术,开发者可以创造出性能优异且视觉效果丰富的WPF应用程序。在实际应用中,开发者应根据项目需求和技术背景,权衡利弊,选择最合适的技术方案。
148 0