String、StringBuffer和StringBuilder三个类的异同

Java提供了三个类,用于处理字符串,分别是String、StringBuffer、StringBuilder。其中StringBuilder是jdk1.5才引入的。

String类有final修饰符修饰,所以String类是不可变的,对象一旦创建,不能改变。
String类中有个value的字节数组成员变量,这个变量用于存储字符串的内容,也是用final修饰,一旦初始化,不可改变。

Java提供了两种主要方式创建字符串:

//方式1
String str = "123";
//方式2
String str = new String("123");

Java虚拟机规范中定义字符串都是存储在字符串常量池中,不管是用方式1还是方式2创建字符串,都会去字符串常量池中查找,如果已经存在,则直接返回,否则创建后返回。

Java编译器在编译Java类时,遇到"abc","hello"这样的字符串常量,会将这些常量放入类的常量区,类在加载时,会将字符串常量加入到字符串常量池中。

含有表达式的字符串常量,不会在编译时放入常量区,例如,String str = “abc”+a;

常量池的最大作用是共享使用,提高程序执行效率。

案例1:

String str1 = "123";
String str2 = "123";
System.out.println(str1==str2);

上面代码运行的结果是true.
运行第一行代码时,先在常量池中创建字符串123对象,然后赋值给str1变量。

运行第二行代码时,发现常量池已经存在123对象,则直接将123对象的地址返回给变量str2。
str1 和 str2 变量指向的地址是一样的,他们是同一个对象,因此运行的结果为true。

在这里插入图片描述
从图中可以看出,str1使用""引号(也是平时所说的字面量)创建字符串,在编译期的时候就对常量池进行判断是否存在该字符串,如果存在则不创建直接返回对象的引用;如果不存在,则先在常量池中创建该字符串实例再返回实例的引用给str1。

案例二:

String str1 = new String("123");
String str2 = new String("123");
String str3 = new String(str2);
System.out.println((str1==str2));
System.out.println((str1==str3));
System.out.println((str3==str2));

上面代码运行的结果是

false
false
false

在这里插入图片描述
从上图可以看出,执行第一行代码时,创建了两个对象,一个存放在字符串常量池中,一个存在于堆中,还有一个对象引用str1存放在栈中。

执行第二行代码时,字符串常量池中已经存在"123"对象,所以只在堆中创建了一个字符串对象,并且这个队形的地址指向常量池中"123"对象的地址,同时在栈中创建一个对象引用str2,引用地址指向堆中创建的对象。

执行第三行代码时,在堆中创建一个字符串对象,这个对象的内存地址指向变量str2所指向的内存地址。
通过new方式创建的字符串对象,都会在堆中开辟一个新内存空间,用于存储常量池中的字符串对象。

对于对象而言, == 操作是用于比较两个独享的内存地址是否一致,所以上面的代码执行的结果都是false.

案例三

//这行代码编译后的效果等同于String str1 = "abcd";
String str1 = "ab"+"cd";
String str2 = "abcd";
System.out.println((str1==str2));

上面代码执行的结果是: true。

使用包含常量的字符串连接创建的也是常量,编译器就能确定了,类加载的时候直接存入字符串常量池,当然同样需要判断字符串常量池中是否已经存在该字符串。

案例四

String str2 = "ab";//一个对象
String str3 = "cd";//一个对象
String str4 = str2 + str3 + "1";
String str5 = "abcd1";
System.out.println((str4==str5));

上面代码执行的结果:false。
当使用" + "连接字符串中含有变量时,由于变量的值是在运行时才能确定。

如果使用的jdk8以前版本的虚拟机,在拼接字符串时,会在jvm堆中生成StringBuilder对象,调用append方法拼接字符串,最后调用StringBuilder的toString方法在jvm堆中生成最终的字符串对象。

str4的对象在堆中,str5的对象在字符串常量池中,所以他们不是同一个对象,所以返回的结果是false。

案例五:

String s5 = new String("2") + new String("3");

因为new String(“2”)创建字符串,也是在运行时才能确定对象内存地址。

案例六

final String str2 = "b";
String str2 = "a" + str1;
String str3 = "ab";
System.out.println((str2==str3));

上面代码执行的结果是true.
str1是常量变量,在编译期就确定,直接放入到字符串常量池中,上面的代码效果等同于:

String str2 = "a" + "b";
String str3 = "ab";
System.out.println((str2==str3));

调用String类的intern()方法,会将堆中的字符串实例放入到字符串常量池中。

案例七:

String str2 = "ab";
String str3 = "cd";
String str4 = str2 + str3 + "1";
str4.intern();
String str5 = "abcd1";
System.out.println((str4==str5));

上面代码执行的结果:true,调用了str4.intern()方法后,将str4放入到字符串常量池中,和str5是同一个实例。

总结:
1、频繁使用 "+"操作拼接字符串时,换成StringBuffer和StringBuilder类的append方法实现。

2、多线程环境下进行大量的拼接字符串操作使用StringBuffer,StringBuffer是线程安全的。

3、单线程环境下进行大量的拼接字符串操作使用StringBuilder,StringBuilder是线程不安全的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
StringStringBufferStringBuilder是Java中用于处理字符串的。它们之间有以下异同: 1. String是不可变的,即一旦创建就不能修改。每次对String进行修改时,都会创建一个新的String对象。这使得String在多次修改时效率较低。而StringBuilderStringBuffer是可变的,可以直接修改字符串内容。 2. StringBufferStringBuilder都是可变的字符串缓冲区,可以进行插入、删除和修改等操作。它们提供了与String似的API,但不保证线程安全。StringBuilder是在Java 5.0中引入的,与StringBuffer相比,StringBuilder不考虑同步锁的开销,因此在单线程操作下效率更高。而StringBuffer考虑了同步锁,因此在多线程环境下使用更安全。 3. 在使用场景上,如果在单线程环境下进行字符串操作,建议使用StringBuilder,因为它的效率更高。而在多线程环境下,为了保证线程安全,应该使用StringBuffer。 综上所述,StringStringBufferStringBuilder之间的主要区别在于可变性和线程安全性。String是不可变的,而StringBufferStringBuilder是可变的,StringBuilder的效率更高,但不保证线程安全,而StringBuffer考虑了线程安全。 #### 引用[.reference_title] - *1* *3* [StringStringBufferStringBuilder三者的异同](https://blog.csdn.net/m0_58052874/article/details/124385405)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [StringStringBufferStringBuilder异同点](https://blog.csdn.net/qq_54217349/article/details/126795527)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值