String、StringBuffer和StringBuilder的详解

目录

一、String讲解

1.String(String字符串常量)

2.String 拼接方式与性能的影响

二、StringBuffer 和 StringBuilder 讲解

1.StringBuffer 和 StringBuilder 使用场景:(StringBuffer、StringBuilder字符串变量)

2.StringBuffer的使用

3.StringBuffer与StringBuilder的线程安全性问题 

4.synchronized的含义:(线程同步机制)

5.String和StringBuffer的效率问题

6.StringBuffer与String的可变性问题。 

三、String、StringBuffer、StringBuilder各指标参数

四、String、StringBuffer、StringBuilder的继承结构

五、String、StringBuffer、StringBuilder在JVM中的原理讲解

1. Java class文件结构 和常量池 

2.JVM运行class文件

3.通过操作码|助忆符|指令 (二进制指令)区别字符串对象的创建方式

六、常见争论

【常见争论1】关于字符串相等关系的争论

【常见争论2】 字符串“+”操作的是否相等

七、String、StringBuffer和StringBuilder知识总结

1.值的可变性

2.线程安全

3.三者性能

4.三者数据量与类型选择与使用推荐

5.数据存储

八、拓展相关知识

1.操作码|助忆符|指令相关讲解

2.String.intern()方法讲解


一、String讲解

1.String(String字符串常量

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

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

2.String 拼接方式与性能的影响

某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:

(1)String对象初始化之前赋值前拼接字符串方式

String S1 = "This is only a" + " simple" + " test";  
StringBuffer Sb = new StringBuffer("This is only a").append(" simple").append(" test");

String对象初始值之前进行赋值,拼接字符串方式比较快。

(2)String对象间的字符串拼接方式

String S2 = “This is only a”; String S3 = “ simple”;
String S4 = “ test”; String S1 = S2 +S3 + S4;//调用StringBuilder的toString()方法在堆中创建的String对象 

多个String对象间的字符串拼接方式比较慢,因为需要调用stringbuilder的方法在堆中创建新的 string对象。

这时候 JVM 会规规矩矩的按照原来的方式去做。

 实例解析:

  你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个 String S1 = “This is only a” + “ simple” + “test”; 其实就是:String S1 = “This is only a simple test”;  所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如(2)string对象间的字符串拼接方式:这时候 JVM 会规规矩矩的按照原来的方式去做。

二、StringBuffer 和 StringBuilder 讲解

1.StringBuffer 和 StringBuilder 使用场景:(StringBuffer、StringBuilder字符串变量)

StringBuffer 和 StringBuilder 特点及使用场景:

1>.应用于对字符串进行修改的时候,特别是字符串对象经常改变的情况下。

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

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

2.StringBuffer的使用

        Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区但不能修改(可以末尾添加和指定地点添加字符却不能修改)。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。

        StringBuffer和StringBuilder 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。

append():始终将这些字符添加到缓冲区的末端

insert():在指定的点添加字符

实例举例:

如果 z 引用一个当前内容是“start”的字符串缓冲区对象,z.append("le") 字符串缓冲区包含“startle”。同样的“start”, z.insert(4, "le") 将更改字符串缓冲区,使之包含“starlet”。

3.StringBuffer与StringBuilder的线程安全性问题 

StringBuffer线性同步,StringBuilder 非线性同步

      StringBuffer和StringBuilder可以算是双胞胎了,这两者的方法没有很大区别。但在线程安全性方面,StringBuffer允许多线程进行字符操作。这是因为在源代码中StringBuffer的很多方法都被关键字synchronized (同步锁)修饰了。

        java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。

4.synchronized的含义:(线程同步机制)

      每一个类对象都对应一把锁,当某个线程A调用类对象中的synchronized方法M时,必须获得对象的锁才能够执行M方法,否则线程A阻塞。一旦线程A开始执行M方法,将独占对象的锁。使得其它需要调用对象的M方法的线程阻塞。只有线程A执行完毕,释放锁后。那些阻塞线程才有机会重新调用M方法。这就是解决线程同步问题的锁机制

        synchronized是java里的一个关键字,可以用来给对象方法或者代码块加锁,当它锁定一个方法或者代码块的时候,同一时刻最多只有一条线程执行这段代码。 

      多线程编程中StringBuffer比StringBuilder要安全 。如果有多个线程需要对同一个字符串缓冲区进行操作的时候,StringBuffer应该是不二选择。

注意: 对于String是否安全的说法,String是不可变的。线程对于堆中指定的一个String对象只能读取,所以很安全。 

5.String和StringBuffer的效率问题

      首先说明一点:StringBuffer和StringBuilder可谓双胞胎,StringBuilder是1.5新引入的,其前身就是StringBuffer。StringBuilder的效率比StringBuffer稍高,如果不考虑线程安全,StringBuilder应该是首选。另外,JVM运行程序主要的时间耗费是在创建对象和回收对象上。

      我们用下面的代码运行1W次字符串的连接操作,测试String,StringBuffer所运行的时间。

//测试代码  
public class RunTime{  
    public static void main(String[] args){  
           ● 测试代码位置1  
          long beginTime=System.currentTimeMillis();  
          for(int i=0;i<10000;i++){  
                 ● 测试代码位置2  
          }  
          long endTime=System.currentTimeMillis();  
          System.out.println(endTime-beginTime);     
    }  
}  

(1) String常量与String(对象间的拼接)变量的"+"操作比较 

▲测试①代码:

(测试代码位置1)
String str="";

(测试代码位置2) 
str="Heart"+"Raid";

        [耗时:  0ms]

▲测试②代码       

(测试代码位置1) 
String s1="Heart"; 

String s2="Raid"; 

String str="";


(测试代码位置2) 
str=
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值