String,StringBuilder,StringBuffer的理解与比较

本文深入探讨了Java中的String、StringBuilder和StringBuffer的区别与应用场景,详细解释了它们的内部实现原理及性能特点。

1.String,StringBuilder,StringBuffer的理解

1.String

String是被 final 修饰的,因此String是不可以被继承以及改变的,每次对String的改变,都会返回一个新的对象

String的底层是用数组实现的

private final char value[];
String s1 = "hello";
String s2 = new String("hello");
String s3 = "hello";
String s4 = new String("hello");
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s2 == s4);

上述代码的执行结果:

false
true
false

s1和s3在创建的时候会现在常量池里面找有没有 “hello” 这个字符,如果有的话,会直接指向这个位置,如果没有的话,会在常量池中创建一块内存空间来存储 “hello” 这个字符,当创建s1的时候,常量池中是没有"hello"这个字符串的,所以它会开辟一块空间来存储"hello" ,而当s3执行的时候,常量池中是有"hello"这个字符的,所以它会直接指向这个"hello",所以s1和s3是相等的

而通过 new String() 的方式来创建对象时,它每次都会在堆上开辟一个新的空间来存储字符串,因此它们之间是不相等的

String s1 = "";
for (int i = 0;i < 1000; i++) {
	s1 += "a";
}

上述的代码在执行的时候JVM会优化拼接方式,每加一次,JVM都会通过创建一个StringBuilder对象,并调用append()方法来实现拼接,如下图。

这样的话会造成一个问题,每一次拼接都会在堆上开辟一片空间,生成一个StringBuilder对象,这样会消耗内存资源
在这里插入图片描述

2.StringBuilder与StringBuffer

StringBuilder与StringBuffer差不多,不过最大的区别就是StringBuffer是线程安全的,而StringBuilder是线程不安全的,因为StringBuffer在许多方法面前都加了synchronized关键字修饰,因此

StringBuilder :效率高但线程不安全
StringBuffer :效率低但线程安全

StringBuilder和StringBuffer的底层也是使用数组实现的

StringBuilder builder = new StringBuilder();
for (int i = 0;i < 1000; i++) {
	builder += "a";
}

这样的话,就不用每次都创建一个StringBuilder对象

2.String,StringBuilder,StringBuffer的比较

总结:
1、String一创建就不能修改,适合用在字符串不需要经常修改的场景

2、StringBuilder和StringBuffer差不多,只是StringBuffer是线程安全的,但是效率偏低,适合用在多线程环境下

3、StringBuilder速度快,线程不安全,适合用在单线程环境下

3.一些小问题

1、以下代码的执行结果是什么?

String a = "helloa";
String b = "hello" + "a":
System.out.println(a == b);

执行结果:

true

因为如果是想上述的直接拼接的方式,在编译的时候就会优化为"hello",所以a和b指向的其实是同一块常量池地址

2、以下代码的执行结果是什么?

String a = "helloa";
String b = "hello":
String c = b + "a":
System.out.println(a == c);

执行结果:

false

如果采用上述的引用拼接的话,在编译时不会优化,所以其实c是在堆内存中新开辟了一片空间,所以它们的引用地址不同,也就是false

3、以下代码的执行结果是什么?

String a = "helloa";
final String b = "hello":
String c = b + "a":
System.out.println(a == c);

执行结果:

true

beifinal修饰的值,在编译期间就会被代替为真正的值,例如上述代码的b其实在编译期间会直接替换为"hello",所以结果为true

4、以下代码在执行过多时候创建了几个对象

String str = new String("hello");

答案是1个,因为在编译的时候会在常量池中创建一个"hello"的对象,在执行的时候会在堆内存中创建一个"hello"对象,虽然总共创建了两个对象,但是在执行的时候就只创建了1个

5、以下代码的执行结果是什么?

public static String hello() {
	return "hello";
}
String a = "helloa";
final String b = hello():
String c = b + "a":
System.out.println(a == c);

执行结果:

false

上一题虽然说过b被final修饰,所以在编译的时候会被代替为实际的值,但是当它调用方法的时候,其实是不一样的,因为当它调用方法时,在编译的时候,并不能确定b的值,所以只有在运行的时候它才能确定b的值,所以是false

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值