String,StringBuffer,StringBuilder相关理解及其区别

String

String是不可变对象, 由String创建的字符的内容是无法修改的,主要原因是其底层使用的是char[]数组,且使用final所修饰如下图
在这里插入图片描述
对于String而言我们应该尽量把它当成一个基本类型来使用 ,而不是当成类,因为当我们使用一String的时候一般仅仅只是为了定义一个字符串,使用new字符去创建一个对象初始化字符串时候会消耗堆栈的空间,十分浪费资源。由于String字符串值是不可改变的,即增添值相当于new一个对象(后面会讲解)

String具体分析

上述只是一个简单的了解,那下面我们来具体分析一下,帮助大家理解

	String a = "123";
	String b =  new String("123");

对于String a = "123"而言,程序在编译时,就会从常量池中找"123"这个字符串,若存在,将地址赋给a,若不存在,创建并赋值地址给a。
可以简单假想为:a -> b

而对于String b = new String("123")而言,程序会在运行时会在栈上创建一个引用对象b,在堆上创建一个空间 存放 new String的对象,由于String对象比较特殊,会在常用池中查找"123"这个字符串,若存在,将地址赋给堆上的String对象,若不存在,创建并赋值地址给b。
可以简单假想为:b -> String ->“123”

如下图所示:
在这里插入图片描述
根据上面所示我们进行测试

		@Test
	public void demo() {	
		String a = "123";
		String b = "123";
		String c = "12"+"3";
		String d = "12";
		String e = d+"3";
		String f = new String("123");
		String g = new String("123");
		
		System.out.println("1. a和b比较:"+(a == b)); 
		System.out.println("2. a和c比较:"+(a == c));
		System.out.println("3. a和e比较:"+(a == e));
		System.out.println("4. a和f比较:"+(a == f));
		System.out.println("5. f和g比较:"+(f == g));
	}

下面是结果:

 1. a和b比较:true
 2. a和c比较:true
 3. a和e比较:false
 4. a和f比较:false
 5. f和g比较:false

字符之间==是比较地址而不是比较内容,比较内容使用equals()。如上所示

  1. 说明a和b引用地址相同,都是指向常量池同一个值,故true
  2. 说明常量String得到的是字符串连接后的完成后的地址,
    实际上String c = "12"+"3"等价于String a = "123",即true
  3. 值得说明的一个地方就是,由于String类型是不可以修改本身的,
    String e = d+"3"实际上是拆分成了两个部分:
    StringBuilder str = new StringBuilder("12")
    String e = str.append("3").toString后面会说明StringBuilder
    可以知道因为e指向的是堆中的Str对象,故比较是false
  4. 由于a和f一个指向常量池,一个指向堆栈,引用不一样,故false
  5. f和g虽然传的参数一样,都指向堆内存中,但是对于new关键字而言每个new会开辟一片新的空间,即f和g指向堆内存中的对象不同,故false

StringBuffer和StringBuilder

StringBuffer是一个可变对象,与String不同的是可以对其字符串进行修改,添加值可以通过它的append()方法实现,可以通过toString()方法转化为String类型
,由于StringBuffer中的大部分方法采用了synchronized关键字修饰,因此线程安全,StringBuffer每次都需要判断锁,故效率会低于StringBuilder

//StringBuffer使用
StringBuffer str = new StringBuffer();//构造方法不传参数时为null
Str.append("123");
String a = Str.toString();

StringBuilder和StringBuffer用法几乎一样,唯一不同是StringBuilder没有synchronized修饰,不是线程安全的,但也因此效率会更优

//StringBuilder使用
StringBuilderstr Str = new StringBuilder();//构造方法不传参数时为null
Str.append("123");
String a = Str.toString();

测试String,StringBuffer,StringBuilder的性能

话不多说直接上代码:

package com.ll.String.demo;

/**
 * 测试String,StringBuffer,StringBuilder的性能
 * @author 李小轮
 *
 */
public class Test {
	@org.junit.Test
	public void demo1() {
		int times = 100000;
		String addstr = "abc";
		String str1 = "";		
		
		//测试String性能
		long start1 = System.currentTimeMillis();
		for(int i = 0;i<times;i++) {
			str1 += addstr;
		}
		long end1 = System.currentTimeMillis();
		
		//测试StringBuffer性能
		StringBuffer str2 = new StringBuffer("");
		long start2 = System.currentTimeMillis();
		for(int i = 0;i<times;i++) {
			str2.append(addstr);
		}
		long end2 = System.currentTimeMillis();
		
		//测试StringBuilder性能
		StringBuilder str3 = new StringBuilder("");
		long start3 = System.currentTimeMillis();
		for(int i = 0;i<times;i++) {
			str3.append(addstr);
		}
		long end3 = System.currentTimeMillis();
		
		System.out.println("这是String:" + (end1-start1));
		System.out.println("这是StringBuffer:" + (end2-start2));
		System.out.println("这是StringBuilder:" + (end3-start3));

	}
}

运行结果:

这是String:14330
这是StringBuffer:4
这是StringBuilder:2

从上面结果也可以看出来,String每次字符增添相当于new一个对象,既耗费时间也浪费资源,而StringBuffer和StringBuilder每次都是操作同一个对象,速度相比String快太多了,StringBuffer和StringBuilder的效率相差不多,不过StringBuffer还是相对StringBuffer要慢一点,也恰好验证了前面的所说。

  • 总结:不对字符进行操作,使用String就够了,而且使用时候不要new,没有必要。而需要经常操作字符的时候,建议使用StringBuffer,因为线程安全。但是实在要追求效率的时候,可以在单线程使用StringBuilder。

第一次写博客,感觉思维还是有些混乱的,不过我想表达的东西应该算是表达完了,建议大家去看看java虚拟机的深入了解,对java而言,基本上很多地方都可以解释得通。小白不容易,我也想有一天当大牛。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值