详细讲解String拼接原理,介绍StringBuilder和StringBuffer

简介: 详细讲解String拼接原理,介绍StringBuilder和StringBuffer

0、思考

       我们都知道真正修改一个String的内容是很难的,而我们平常却可以通过‘+=’来拼接字符串

public static void main(String[] args) {
        String str = new String("Hello");
        str += " World";
        System.out.println(str);
    }

        这是为什么呢?我们接着往下看。

1、讲解String拼接字符串原理

Ⅰ底层字符接实现逻辑

       我们来看一下上述代码的底层实现逻辑

      我们发现,当我们执行 “str += " World";”时底层其实走四步


先创建一个StringBuilder对象,并调用无参数的构造方法。

StringBuilder对象调用append方法,把str内部 “Hello” 拼接到内部。

StringBuilder对象再次调用append方法,把 " World" 拼接到内部。

最后StringBuilder对象调用toString方法,把拼接好的字符串传给str。

"":表示构造方法

()V:表示无参数的构造方法


上述代码其实就等同于

public static void main(String[] args) {
        String str = new String("Hello");
        StringBuilder sb = new StringBuilder();
        sb.append(str);
        sb.append(" World");//拼接字符串
        str = sb.toString();
        System.out.println(str); //输出Hello World
    }

所以我们每次拼接字符串时,都会创建一个对象进行该操作,而非在String内部进行。

注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:

String变为StringBuilder: 利用StringBuilder的构造方法或append()方法

StringBuilder变为String: 调用toString()方法

Ⅱ使用不同方法拼接字符串事件比较

       我用两种方法拼接字符串,我们来看一下各种运行时间

public static void main(String[] args) {
        //普通方法拼接
        long start = System.currentTimeMillis();
        String s1 = "";
        for(int i = 0; i < 10000; ++i){
            s1 += i;
        } long end = System.currentTimeMillis();
        long  time = end-start;
        System.out.println("普通方法拼接时间:"+ time);
        //用StingBuilder类拼接
        start = System.currentTimeMillis();
        StringBuilder s3 = new StringBuilder();
        for(int i = 0; i < 10000; ++i){
            s3.append(i);
        } end = System.currentTimeMillis();
        time = end-start;
        System.out.println("StringBuilder 拼接时间:"+ time);
    }

结果如下:


我们用直接使用String类拼接的字符串的话,每拼接一次就会创建一个新的对象,次数一多运行时间就会变长。所以当我们频繁修改字符串的情况考虑使用StringBuilder类进行操作。

我再举一个LeetCode上实际操作的例题,如下:

StringBuilder类拼接 1ms

普通拼接 23ms


大家感兴趣了,可以去做一下这道题:根据二叉树创建爱字符串

Ⅲ了解StringBuilder类修改内部字符串过程

我们看下图



      首先在栈中创建一个StringBuilder变量sb,然后在堆中开辟一块空间,被sb引用。

append方法我们可以看做把参数传给 StringBuilder对象

      当sb第一次调用append方法时,编译器会先把“Hello”放到字符串常量池中,然后再把“Hello”传给sb引用对象。


      当sb第二次调用append方法时,编译器同样会先把 " World" 放到字符串常量池中,但此刻 sb 并不会new一个新的对象来接受append方法传来的 " World",而是在原来的对象内部直接进行拼接。

我们观察 append方法 就会发现,append方法最后返回的是 "this"!也就是原来的对象。

这也就是为什么StringBuilde对象能修改字符串的原因。

2、介绍StringBuilder和StringBuffer及一些常用的方法

  上面我们介绍了 StringBuilder,其实为了方便字符串的修改,Java中又提供StringBuffer类。


   这两个类的大部分功能是相同的。如下

public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        sb.append("你好!");
        sb.append("我是威威");
        String str = sb.toString();
        System.out.println(str);
    }

         

而除了append和toString之外,StringBuilder和StringBuffer中包含各种各样的方法。


这里介绍一些常用的,其它需要用到了大家可参阅 StringBuilder在线文档


以下以StringBuilder为例,StringBuffer中方法类似


方法 说明
StringBuff append(String
str)
在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、
double、float、int、long、Object、String、StringBuff的变量
char charAt(int index) 获取index位置的字符
int length() 获取字符串的长度
int capacity() 获取底层保存字符串空间总的大小
void ensureCapacity(int
mininmumCapacity)
扩容
void setCharAt(int index,
char ch)
将index位置的字符设置为ch
int indexOf(String str) 返回str第一次出现的位置
int indexOf(String str, int
fromIndex)
从fromIndex位置开始查找str第一次出现的位置
int lastIndexOf(String str) 返回最后一次出现str的位置
int lastIndexOf(String str,
int fromIndex)
从fromIndex位置开始找str最后一次出现的位置
StringBuff insert(int
offset, String str)
在offset位置插入:八种基类类型 & String类型 & Object类型数据
StringBuffer
deleteCharAt(int index)
删除index位置字符
StringBuffer delete(int
start, int end)
删除[start, end)区间内的字符
StringBuffer replace(int
start, int end, String str)
将[start, end)位置的字符替换为str
String substring(int start) 从start开始一直到末尾的字符以String的方式返回
String substring(int
start,int end)
将[start, end)范围内的字符以String的方式返回
StringBuffer reverse() 反转字符串
String toString() 将所有字符按照String的方式返回


3、StringBuilder和StringBuffer区别

为了对比StringBuilder和StringBuffer,我们来看一下他俩 append方法的具体代码

我们发现,StringBuffer的append方法中,多了一个 synchronized,而 synchronized 含义是保护线程安全。平时遇到多线程时,用StringBuffer的比较多。


所以StringBuilder和StringBuffer区别在于:


       StringBuffer采用同步处理,属于线程安全操作;


       StringBuilder未采用同步处理,属于线程不安全操作;

拓展:如何打开字节文件

我们在idea操作中,点击上面的小框

点击后,找到Openin后点击Explorer,这时会弹出一个文件夹。


点击 2022-7-12,找到out文件,进去点击production,再点击 2022-7-12,之后就能看见我们.class文件。

这里 2022-7-12 是我自己创建的文件名,而且我的 .class 文件在 demo2 包中,所以多跳了一步。


然后按着Shift键,右键点击 .class 文件,然后点击 “PowerShell”,就会弹出一个窗口

尽量点击文件中间空白部分,部分可能找不到 “PowerShell”,这个选项

接着我们在窗口中输入 javap -c 文件名,就能看到我们代码编译后字节码啦


到此,本节内容就讲完了,有错误的地方希望大家能批评指正,别忘了点赞👍+收藏⭐️哦

     😜  关注我!带来等多精彩🎉🎉


相关文章
|
12天前
|
安全
String、StringBuffer、StringBuilder的区别
String 由 char[] 数组构成,使用了 final 修饰,对 String 进行改变时每次都会新生成一个 String 对象,然后把指针指向新的引用对象。 StringBuffer可变并且线程安全;有一定缓冲区容量,字符串大小没超过容量,不会重新分配新的容量,适合多线程操作字符串; StringBuiler可变并且线程不安全。速度比StringBuffer更快,适合单线程操作字符串。 操作少量字符数据用 String;单线程操作大量数据用 StringBuilder;多线程操作大量数据用 StringBuffer
|
3月前
|
安全 Java
String、StringBuffer、StringBuilder的区别
这篇文章讨论了Java中String、StringBuffer和StringBuilder的区别。String是不可变的,每次操作都会产生新的对象,效率低且浪费内存。StringBuilder可以在原字符串基础上进行操作,不开辟额外内存,弥补了String的缺陷。StringBuffer和StringBuilder类似,但StringBuffer的方法是线程安全的。文章还列举了StringBuffer的常用方法,并提供了使用示例代码。最后总结了这三者的主要区别。
String、StringBuffer、StringBuilder的区别
|
2月前
|
canal 安全 索引
(StringBuffer和StringBuilder)以及回文串,字符串经典习题
(StringBuffer和StringBuilder)以及回文串,字符串经典习题
37 5
|
2月前
|
存储 安全 Java
String、StringBuffer 和 StringBuilder 的区别
【10月更文挑战第21天】String、StringBuffer 和 StringBuilder 都有各自的特点和适用场景。了解它们之间的区别,可以帮助我们在编程中更合理地选择和使用这些类,从而提高程序的性能和质量。还可以结合具体的代码示例和实际应用场景,进一步深入分析它们的性能差异和使用技巧,使对它们的理解更加全面和深入。
24 0
|
3月前
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
40 0
java基础(13)String类
|
2月前
|
Java
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
本文深入探讨了Java中方法参数的传递机制,包括值传递和引用传递的区别,以及String类对象的不可变性。通过详细讲解和示例代码,帮助读者理解参数传递的内部原理,并掌握在实际编程中正确处理参数传递的方法。关键词:Java, 方法参数传递, 值传递, 引用传递, String不可变性。
58 1
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
|
2月前
|
安全 Java 测试技术
Java零基础-StringBuffer 类详解
【10月更文挑战第9天】Java零基础教学篇,手把手实践教学!
34 2
|
3月前
|
安全 Java
String类-知识回顾①
这篇文章回顾了Java中String类的相关知识点,包括`==`操作符和`equals()`方法的区别、String类对象的不可变性及其好处、String常量池的概念,以及String对象的加法操作。文章通过代码示例详细解释了这些概念,并探讨了使用String常量池时的一些行为。
String类-知识回顾①
|
2月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
22 1
|
2月前
|
数据可视化 Java
让星星月亮告诉你,通过反射创建类的实例对象,并通过Unsafe theUnsafe来修改实例对象的私有的String类型的成员属性的值
本文介绍了如何使用 Unsafe 类通过反射机制修改对象的私有属性值。主要包括: 1. 获取 Unsafe 的 theUnsafe 属性:通过反射获取 Unsafe类的私有静态属性theUnsafe,并放开其访问权限,以便后续操作 2. 利用反射创建 User 类的实例对象:通过反射创建User类的实例对象,并定义预期值 3. 利用反射获取实例对象的name属性并修改:通过反射获取 User类实例对象的私有属性name,使用 Unsafe`的compareAndSwapObject方法直接在内存地址上修改属性值 核心代码展示了详细的步骤和逻辑,确保了对私有属性的修改不受 JVM 访问权限的限制
56 4