String和StringBuffer的区别

本文详细解析Java中String与StringBuffer的区别,包括不可变性、内存分配、效率对比及应用场景,通过代码实例深入理解两者在字符串操作中的优劣。

string与stringbuffer的区别

########################简单说来########################
String对象内容是不可改变的,StringBuffer是可以改变的,别且高效。
1.String
String a = "123";
a = a + "456";
上面两句,虽然a的值最终改变了,但是实际上在编译的时候,第一句a是一个对象,被分配了一个地址,第二句执行时,原来的a被释放,然后重新分配。
a 原本指向一 String object instance ("123"), a + "456" 会造出另一新的 String object instance ("123456"), 然后a再指向这新的 String instance。
2.StringBuffer
StringBuffer b = new StringBuffer("asd");
b.append("fgh");
在这个过程中,只存在b这么一个对象,b 一直都指向一个 StringBuffer instance。*.append 也只是改变此 instance 的内容而已。

########################稍复杂说来########################
在我以前的了解中,String是一个final Class, StringBuffer不是。所以对于
String a = "yacht"; String b = "yacht1"; String c = a + b ;
存在一个对象拷贝构造和解析的消耗问题;对于一个StringBuffer来说,
StringBuffer sb = new StringBuffer();sb.append("yacht") ; sb.append("yacht1");
因为StringBuffer是一个可以实例化的类,而且它的内建机制是维护了一个capacity大小的字符数组,所以它的append操作不存在对象的消耗问题,所以我觉得如果存在String连接这种事情,StringBuffer来做会好很多。
但事情并不是这么简单,看下面代码
String a = "yacht1" + "yacht2" + "yacht3" + "yacht4";
StringBuffer sb = new StringBuffer(); sb.append("yacht1") ; sb.append("yacht2"); sb.append("yacht3") ; sb.append("yacht4");     String a = sb.toString();
如果按照我先前说的看法,红色的效率肯定比蓝色的低,但经过测试不是这样,为什么?这里,我们需要理解程序过程的两个时期,一个是编译时,一个是运行时,在编译时,编译器会对你的程序做出优化,所以红色的String a会被优化成yacht1yacht2yacht3yacht4,而蓝色的StringBuffer只会在运行时才处理。所以效率是不一样的。
如果代码是这样的:
String a ; for(int i = 0; i< 100000;i++){ a += String.valueOf(i) ;}
StringBuffer sb = new StringBuffer(); for(int i = 0; i< 100000;i++){ sb.append(i) ;} String a = sb.toString();
如果是这种情况的话,红色的效率就大大不如蓝色,区别在哪里,就在于运行时和编译时的优化问题上!
我在想,我们要做一个好的writer,不仅要知道怎么用,还要知道怎么用好,这需要内功的修练,花拳绣腿是招架不住的!

########################稍微延伸说来########################
public class xxx {
public static void main(String[] args) {
String s1 = "You are hired!";
String s2 = "You are hired!";
if (s1==s2) {
System.out.println("一个内存空间");
} else {
System.out.println("不是一个内存空间");
}
}
}
打印的结果是:一个内存空间。这里==的意义是两个操作数是否指向同一个对象。
可见s2在不用new创建的情况下会自动检索到具有相同内容的内存空间中共享,那么既然s1和s2共享了同一个对象,再看下面的代码:
public class xx {
public static void main(String[] args) {
String s1 = "You are hired!";
String s2 = "You are hired!";
s1 = s1.replace('h','f');
System.out.println(s1);
if (s1==s2) {
System.out.println("一个内存空间");
} else {
System.out.println("不是一个内存空间");
}
}
}
代码结果是
You are fired!
不是一个内存空间
可见,String中s1的内容虽然被改写,但是已经不在是原来第一次分配到的那个内存空间,也就是String类的内容能被改变,但一旦改变系统将为其分配新的内存
说到与stringBuffer的区别,从根本上来说应该是
stringBuffer在做字符长度变动的时候将继续使用原来的内存空间,不新分配.
而String的长度一旦变动,就如上面的例子一样,其内部将分配新的内存空间


########################面试的老题目了########################
其实我知道使用的区别,StringBuffer必须new出来,StringBuffer的append的效率比string的+=的效率高,仔细研究发现还有很大的区别,看了看以前scjp的考题
public class Test {
public static void stringReplace (String text) {
      text = text.replace('j' , 'i');
    }
public static void bufferReplace (StringBuffer text) {
      text = text.append("C");
    }
   public static void main (String args[]) {
       String textString = new String ("java");
       StringBuffer textBuffer = new StringBuffer ("java");
   
       stringReplace (textString);
       bufferReplace (textBuffer);
   
       System.out.println (textString + textBuffer);
     }
   }
答案是 javajavaC而不是iavajavaC
这是String参数传递,是不可变的(immutable).
而题目中第七行text = text.append (“C”),append方法会改变text中的值
而这个text与main中的textBuffer是指向同一个对象,所以对应的输出是javac。
string的值永远不会改变!

String a = "a";//假设a指向地址0x0001,
a = "b";//重新负值后a指向地址0x0002,但0x0001地址中保存的"a"依旧存在,但已经不再是a所指向的。
从表面上看String类型的对象改变了值,但事实是他不能改变值,只能改变指向的地址

StringBuffer则不同,直接改变指向的地址中保留的值
还有
StringBuffer s1 = new StringBuffer("a");
StringBuffer s2 = new StringBuffer("a");
s1.equals(s2)//为什么是false
String s1 = new String("a");
String s2 = new String("a");
s1.equals(s2)//为什么是true
StringBuffer类中没有重新定义equals这个方法,因此这个方法就来自Object类,而Object类中的equals方法是用来比较地址的,所以等于false.
String类中重新定义了equals这个方法,而且比较的是值,而不是地址。所以会是true。


总而言之,String的值永远不会改变! StringBuffer的地址永远不变!

基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究(Matlab代码实现)内容概要:本文围绕“基于可靠性评估序贯蒙特卡洛模拟法的配电网可靠性评估研究”,介绍了利用Matlab代码实现配电网可靠性的仿真分析方法。重点采用序贯蒙特卡洛模拟法对配电网进行长时间段的状态抽样与统计,通过模拟系统元件的故障与修复过程,评估配电网的关键可靠性指标,如系统停电频率、停电持续时间、负荷点可靠性等。该方法能够有效处理复杂网络结构与设备时序特性,提升评估精度,适用于含分布式电源、电动汽车等新型负荷接入的现代配电网。文中提供了完整的Matlab实现代码与案例分析,便于复现扩展应用。; 适合人群:具备电力系统基础知识Matlab编程能力的高校研究生、科研人员及电力行业技术人员,尤其适合从事配电网规划、运行与可靠性分析相关工作的人员; 使用场景及目标:①掌握序贯蒙特卡洛模拟法在电力系统可靠性评估中的基本原理与实现流程;②学习如何通过Matlab构建配电网仿真模型并进行状态转移模拟;③应用于含新能源接入的复杂配电网可靠性定量评估与优化设计; 阅读建议:建议结合文中提供的Matlab代码逐段调试运行,理解状态抽样、故障判断、修复逻辑及指标统计的具体实现方式,同时可扩展至不同网络结构或加入更多不确定性因素进行深化研究。
`String`、`StringBuilder` `StringBuffer` 都是 Java 中用于处理字符串的类,但它们在可变性、线程安全性性能方面存在显著区别。 ### 可变性 - **`String`**:`String` 的值是不可变的,每次对 `String` 进行操作(如拼接、替换等)时,都会生成一个新的 `String` 对象,原来的对象仍然存在于内存中,如果没有被再次引用,则会被垃圾回收。例如: ```java String str = "Hello"; str = str + " World"; // 这里会创建一个新的 String 对象 ``` - **`StringBuilder` `StringBuffer`**:这两个类的值是可变的,它们在进行字符串操作时,不会创建新的对象,而是直接在原对象的基础上进行修改,避免了频繁创建对象带来的性能开销内存浪费[^3]。例如: ```java StringBuilder sb = new StringBuilder("Hello"); sb.append(" World"); // 直接在原对象上进行修改 ``` ### 线程安全性 - **`String`**:由于 `String` 是不可变的,因此它是线程安全的,多个线程可以同时访问同一个 `String` 对象,而不会出现数据不一致的问题。 - **`StringBuilder`**:`StringBuilder` 不是线程安全的,它的方法没有使用 `synchronized` 关键字修饰,因此不能在多线程环境下使用,否则可能会出现数据不一致的问题。例如,在多线程环境下对同一个 `StringBuilder` 对象进行操作,可能会导致部分操作丢失或数据混乱[^2][^3]。 - **`StringBuffer`**:`StringBuffer` 是线程安全的,它的很多方法都带有 `synchronized` 关键字,保证了在多线程环境下对 `StringBuffer` 对象的操作是线程安全的。例如,在多线程环境下对同一个 `StringBuffer` 对象进行操作,不会出现数据不一致的问题,但由于加锁会带来一定的性能开销,因此在单线程环境下使用 `StringBuffer` 会比 `StringBuilder` 慢[^2][^3]。 ### 性能 - **`String`**:由于每次操作都会生成新的对象,因此在进行大量字符串拼接等操作时,`String` 的性能较差,会消耗大量的内存 CPU 资源。 - **`StringBuilder`**:在单线程环境下,`StringBuilder` 的性能比 `StringBuffer` 高,因为它不需要进行线程同步,避免了加锁带来的性能开销。因此,在单线程环境下进行大量字符串操作时,建议使用 `StringBuilder`。 - **`StringBuffer`**:由于需要进行线程同步,`StringBuffer` 的性能相对较低。但在多线程环境下,为了保证数据的一致性,必须使用 `StringBuffer`。 ### 总结 - 如果字符串内容不需要改变,或者只进行少量的字符串操作,建议使用 `String`。 - 如果在单线程环境下进行大量的字符串操作,建议使用 `StringBuilder`,因为它的性能更高。 - 如果在多线程环境下进行大量的字符串操作,建议使用 `StringBuffer`,以保证线程安全。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值