Java常用API学习之StringBuffer详解

本章介绍StringBuffer以及它的API的详细使用方法,欢迎各位同学转载,但转载务必注明出处~

  • 概念

StringBuffer线程安全可变字符序列。每个字符串缓冲区都有一定的容量。只要字符串缓冲区所包含的字符序列的长度没有超出此容量,就无需分配新的内部缓冲区数组。如果内部缓冲区溢出,则此容量自动增大。从 JDK 5 开始,为该类补充了一个单个线程使用的等价类,即 StringBuilder。与该类相比,通常应该优先使用StringBuilder类,因为它支持所有相同的操作,但由于它是异步的,所以速度更快。

  • 构造方法

构造方法摘要

StringBuffer() 

          构造一个其中不带字符的字符串缓冲区,其初始容量为 16 个字符

StringBuffer(CharSequence seq) 

          public java.lang.StringBuilder(CharSequence seq) 构造一个字符串缓冲区,它包含与指定的 CharSequence 相同的字符,CharSequence 是一个接口,所以我们传的参数应该是它的实现类

CharBuffer, Segment, String, StringBuffer, StringBuilder

StringBuffer(int capacity) 

          构造一个不带字符,但具有指定初始容量的字符串缓冲区。

StringBuffer(String str) 

          构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。这样创建的StringBuffer对象的容量是16+str.length()

 

代码示例:

package String;

public class StringBufferDemo {
	public static void main(String[] args) {
		StringBuffer buffer = new StringBuffer();
		StringBuffer buffer2 = new StringBuffer(buffer);
		StringBuffer buffer3 = new StringBuffer(50);
		StringBuffer buffer4 = new StringBuffer("StringBuffer");

		System.out.println("buffer == " + buffer);
		System.out.println("buffer的容量:" + buffer.capacity());
		System.out.println("buffer的长度:" + buffer.length());

		System.out.println("buffe2r == " + buffer2);
		System.out.println("buffer2的容量:" + buffer2.capacity());
		System.out.println("buffer2的长度:" + buffer2.length());

		System.out.println("buffer3 == " + buffer3);
		System.out.println("buffer3的容量:" + buffer3.capacity());
		System.out.println("buffer3的长度:" + buffer3.length());

		System.out.println("buffer4 == " + buffer4);
		System.out.println("buffer4的容量:" + buffer4.capacity());
		System.out.println("buffer4的长度:" + buffer4.length());
	}
}

运行结果:

buffer == 
buffer的容量:16
buffer的长度:0
buffe2r == 
buffer2的容量:16
buffer2的长度:0
buffer3 == 
buffer3的容量:50
buffer3的长度:0
buffer4 == StringBuffer
buffer4的容量:28
buffer4的长度:12

buffer的值是“空”(不是真的空),说明StringBuffer重写了toString方法,否则会打印对象地址值。

buffer的容量是16,说明无参构造方法创建的对象初始容量为 16 个字符。

buffer4的容量是28,说明传入参数为String的构造方法创建的对象容量为16+string.length()。

  • StringBuffer的添加功能:

	public static void main(String[] args) {
		/**
		 * StringBuffer的添加功能: public StringBuffer append(Object
		 * obj):表明可以把任意类型数据添加到字符串缓冲区里面,并返回字符串缓冲区本身
		 * 
		 * public StringBuffer insert(int offset,Object
		 * obj):表明在指定位置把任意类型的数据插入到字符串缓冲区里面,并返回字符串缓冲区本身
		 */
		// 创建字符串缓冲区对象
		StringBuffer sb = new StringBuffer();

		StringBuffer sb2 = sb.append("hello");
		System.out.println("sb:" + sb);
		System.out.println("sb2:" + sb2);
		System.out.println(sb == sb2);

	}

运行结果:

sb:hello
sb2:hello
true
运行结果足以说明StingBuffer拼接其他内容时,没有重新创建新的StringBuffer对象。

既然通过append拼接之后返回的还是StringBuffer本身,那么我们可以不断地拼接,像这样:

StringBuffer sb = new StringBuffer();
sb.append("hello");
sb.append("world");
sb.append("java");

也可以进行链式编程,像这样:sb.append("hello").append("world").append("java");

添加功能还有insert(int offset, Object obj),它是指在指定索引处offset插入obj,代码示例:

StringBuffer sb = new StringBuffer("hello");
sb.insert(2, 6);
System.out.println("sb:" + sb);

运行结果:sb:he6llo

  • StringBuffer的删除功能

 public StringBuffer deleteCharAt(int index):删除指定位置的字符,并返回本身
 public StringBuffer delete(int start,int end):删除从指定位置start开始到指定位置end(不包含end处的元素,java中大多数情况下都是包左不包右)结束的内容,并返回本身

代码示例:

1.删除指定位置字符

StringBuffer buffer = new StringBuffer("hello world java");
// 刪除字符e
buffer.deleteCharAt(1);
System.out.println("刪除e之后,buffer == " + buffer);

运行结果:刪除e之后,buffer == hllo world java

2.删除指定的一段字符串

StringBuffer buffer = new StringBuffer("hello world java");
// 需求:删除world这个字符串,肿么办?
buffer.delete(6, 11);
System.out.println("删除world,buffer == " + buffer);

运行结果:删除world,buffer == hello  java

用这个方法我们也可以将StringBuffer内容清空:

// 需求:删除所有的数据
buffer.delete(0, buffer.length());
System.out.println("清空內容後,buffer == " + buffer);
  • StringBuffer的替换功能

我们把world替换成“节日快乐”

StringBuffer buffer = new StringBuffer("hello world java");
buffer.replace(6, 11, "节日快乐");
System.out.println("buffer == " + buffer);

运行结果:buffer == hello 节日快乐 java

  • StringBuffer的翻转功能

public StringBuffer reverse()

代码示例:

StringBuffer buffer = new StringBuffer();
// 添加数据
buffer.append("渝不老终,习成你悦\n医无石药,疾成你喜");
// 翻转内容
buffer.reverse();
System.out.println(buffer);

 运行结果:

喜你成疾,药石无医
悦你成习,终老不渝

  • StringBuffer的截取功能

 public String substring(int start)
 public String substring(int start,int end)

注意:StringBuffer的截取功能返回值类型不再是StringBuffer本身了,而是String

代码示例:

public class StringBufferDemo {
	public static void main(String[] args) {
		StringBuffer buffer = new StringBuffer();
		buffer.append("桃之夭夭,灼灼其华");
		String str1 = buffer.substring(5);
		String str2 = buffer.substring(5, buffer.length());
		System.out.println("str1 = " + str1);
		System.out.println("str2 = " + str2);
	}
}

运行结果:

str1 = 灼灼其华
str2 = 灼灼其华
看了运行结果不知道大家有没有这样的疑问,substring方法调用了两次,第一次调用时已经把“桃之夭夭,”截掉了,第二次截取时传入参数5。按理来说“灼灼其华”只有四个字,这样做会抛异常StringIndexOutOfBoundsException,但为什么没有抛异常呢?这是因为我们在截取的时候,返回结果是String,而StringBuffer本身是没有变的,所以第二次截取还是从第一个“灼”字开始截。

而且我们通过查看源码,可以看到substring(int start)其实调用的是substring(int start,int end)。

  • StringBuffer的常规操作

1.StringBuffer和String的相互转换

		// String转StringBuffer
		String str = "桃李春风一杯酒,江湖夜雨十年灯。";
		// 方式一:通过StringBuffer的构造方法
		StringBuffer buffer = new StringBuffer(str);
		System.out.println("buffer == " + buffer);
		// 方式二:通过append或者insert方法
		buffer.delete(0, buffer.length());
		buffer.append(str);
		System.out.println("buffer == " + buffer);
		buffer.delete(0, buffer.length());
		buffer.insert(0, str);
		System.out.println("buffer == " + buffer);
		System.out.println("---------------------------");

		// StringBuffer转String
		StringBuffer buffer2 = new StringBuffer("桃李春风一杯酒,江湖夜雨十年灯。");
		// 方式一:String的构造方法
		String str2 = new String(buffer2);
		// 方式二:toString方法
		String str3 = buffer2.toString();
		System.out.println("str2 == " + str2);
		System.out.println("str3 == " + str3);

运行结果:

buffer == 桃李春风一杯酒,江湖夜雨十年灯。
buffer == 桃李春风一杯酒,江湖夜雨十年灯。
buffer == 桃李春风一杯酒,江湖夜雨十年灯。
---------------------------
str2 == 桃李春风一杯酒,江湖夜雨十年灯。
str3 == 桃李春风一杯酒,江湖夜雨十年灯。

2.数组转成字符串

public class StringBufferDemo {
	public static void main(String[] args) {
		// 把数组拼接成一个字符串
		int[] nums = { 2, 5, 6, 8, 9 };
		String result=arrToString(nums);
		System.out.println("result == " + result);

	}

	private static String arrToString(int[] nums) {
		StringBuffer buffer = new StringBuffer("[");
		for (int i = 0; i < nums.length; i++) {
			if (i == nums.length - 1) {
				buffer.append(nums[i]+"]");
			} else {
				buffer.append(nums[i] + ",");
			}
		}
		return buffer.toString();
	}
}

3.判断字串是否对称

public class StringBufferDemo {
	public static void main(String[] args) {
		System.out.println("请输入您要判断的字串:");
		Scanner sc = new Scanner(System.in);
		String str = sc.nextLine();
		boolean isSymmetrical = isSymmetrical(str);

		System.out.println("isSymmetrical == " + isSymmetrical);

	}

	private static boolean isSymmetrical(String str) {
		return str.equals(new StringBuffer(str).reverse().toString());
	}

}

运行结果:

请输入您要判断的字串:
客上天然居,居然天上客
isSymmetrical == true

  • 面试题

1.String、StringBuffer、StringBuilder三者的区别

String 类代表字符串,Java 程序中的所有字符串字面值(如 "abc" )都是字符串对象;字符串是常量,它们的值在创建之后不能更改。我们把一个字符串字面值直接赋值给Stirng的引用时,jvm会先在字符串常量池中找这个字面值,如果有就直接返回,没有的话就会创建并返回。而StringBuffer和StringBuilder都是可变字符序列,类似于String的字符串缓冲区,可以通过append、delete等方法改变它的长度和内容。从线程安全角度讲的话,StringBuffer由于加了同步锁,所以安全性优于StringBuilder,比如在银行、医院、政府官网开发中使用StringBuffer。从效率角度讲的话,如果操作大量字符串数据,StringBuilder>StringBuffer>String,如果操作少量数据,String效率最高。

解析:

我们查看String源码可以了解到,String类是通过char数组保存字符串,且char数组被final修饰,表明字符串的值一旦创建就不可更改。

再看看concat和replace方法,这表明操作String不会影响原有对象,而是生成一个新的对象。

StringBuffer和StringBuilder都继承自AbstractStringBuilder,内容和长度都是可变的。

由于StringBuffer加了同步锁,所以安全性高,但是更耗时

我们不妨做个小测试,看看它们三个各自的效率,直接贴代码:

public class StringBufferDemo {
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		String str = new String();
		for (int i = 0; i < 5200; i++) {
			str += i + ",";
		}
		System.out.println("String拼接消耗时间:" + (System.currentTimeMillis() - start));

		long start2 = System.currentTimeMillis();
		StringBuffer buffer = new StringBuffer();
		for (int i = 0; i < 5200; i++) {
			buffer.append(i + ",");
		}
		System.out.println("StringBuffer拼接消耗时间:" + (System.currentTimeMillis() - start2));

		long start3 = System.currentTimeMillis();
		StringBuilder build = new StringBuilder();
		for (int i = 0; i < 5200; i++) {
			build.append(i + ",");
		}
		System.out.println("StingBuilder拼接消耗时间:" + (System.currentTimeMillis() - start3));
	}

}

运行结果:

String拼接消耗时间:57
StringBuffer拼接消耗时间:3
StingBuilder拼接消耗时间:2

2.String与StringBuffer形参传递有什么区别?

先贴代码:

package String;

public class StringBufferDemo {
	public static void main(String[] args) {
		String str1 = "相恨不如潮有信,";
		String str2 = "相思始觉海非深。";
		System.out.println(str1 + str2);
		change(str1, str2);
		System.out.println(str1 + str2);

		StringBuffer buffer1 = new StringBuffer("相恨不如潮有信,");
		StringBuffer buffer2 = new StringBuffer("相思始觉海非深。");
		System.out.println(buffer1 + "" + buffer2);
		change(buffer1, buffer2);
		System.out.println(buffer1 + "" + buffer2);

	}

	private static void change(StringBuffer buffer1, StringBuffer buffer2) {
		buffer1 = buffer2;
		buffer2.append(buffer1);
	}

	private static void change(String str1, String str2) {
		str1 .concat(str2);
		str2 += str1;
	}

}

运行结果:

相恨不如潮有信,相思始觉海非深。
相恨不如潮有信,相思始觉海非深。
相恨不如潮有信,相思始觉海非深。
相恨不如潮有信,相思始觉海非深。相思始觉海非深。

在java中,基本数据类型是值传递,形式参数的改变不影响实际参数,而引用类型是引用地址值的传递,形式参数的改变直接影响实际参数。String是个特例,它虽然是引用类型,形参传递却跟基本数据类型相似。Stirng 实参地址传给形参 ,形参有了地址,在change方法中,它在做运算的时候(str2 += str1;) 却新建了一个字符串"相恨不如潮有信,相思始觉海非深。" 放在常量池中,再加上之前的两个(s1,s2),一共有三个地址。change方法中的s2指向"相恨不如潮有信,相思始觉海非深。",但主方法中的s1、s2依然指向的原来的地址("相恨不如潮有信,"、"相思始觉海非深。"),其中的内容没有任何的改变,所以说是值传递。其实究其原因还是那句话,String一旦被创建就不能再被改变。

欢迎大家评论指出我写的不对的地方,我会及时更正。也欢迎大家提出疑问,我看到会第一时间回复!

欢迎转载>-<,转载请注明出处:https://mp.csdn.net/postedit/89005755 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值