String、StringBuffer、StringBuilder 解析

/ 0评 / 0

在开发过程中,我们最常用的就是对字符串进行操作了,在Java中,与字符串相关的类有这么3个:String、StringBuffer、StringBuilder,下面就来介绍下这三个类的区别。

String

JDK的解释是 “Strings are constant; their values cannot be changed after they are created”也就是说String对象一旦被创建就是固定不变的了,这样的一点好处就是可以多线程之间访问,因为只读不写。Strings类代表字符串。Java 程序中的所有字符串字面值(如 "abc")都作为此类的实例实现。

字符串是常量;它们的值在创建之后不能更改。字符串缓冲区支持可变的字符串。因为 String 对象是不可变的,所以可以共享

一般情况下我们以下面两种方式创建一个String对象。

2012040220432485

两种方式是有区别的,这和java的内存管理有关,前面已经说过,string创建之后是不可变的,所以按照第一种方式创建的字符串常量池中,常量池就是用来保存在编译阶段确定好了大小的数据,一般我们定义的int等基本数据类型就保存在这里。其具体的一个流程就是,编译器首先检查常量池,看看有没有一个“string”,如果没有则创建。如果有的话,则直接把str1指向那个位置。

第二种创建字符串的方法是通过new关键字,还是java的内存分配,java会将new的对象放在堆中,这一部分对象是在运行时创建的对象。所以我们每一次new的时候,都会创建不同的对象,即便是堆中已经有了一个一模一样的。

下面举一个例子:

String str1 = "string";
String str4 = "string";
String str2 = new String("string");
String str3 = new String("string");
        
/*用于测试两种创建字符串方式的区别*/
System.out.println(str1 == str4);
System.out.println(str2 == str3);
System.out.println(str3 == str1);
        
str3 = str3.intern(); //一个不常见的方法
System.out.println(str3 == str1);

这个的运行结果是  

true    //解释:两个字符串的内容完全相同,因而指向常量池中的同一个区域

false   //解释:每一次new都会创建一个新的对象

false  // 解释: 注意==比较的是地址,不仅仅是内容  

true  //介绍一下intern方法,这个方法会返回一个字符串在常量池中的一个地址,如果常量池中有与str3内容相同的string则返回那个地址,如果没有,则在常量池中创建一个string后再返回。实际上,str3现在指向了str1的地址。

字符串的比较不能直接使用==,因为==比较的是地址,应该使用String类提供的equals()方法。

在使用java的过程中,经常看到的一种写法是

String str1 = "hello";

String str = str1 + "world";

这样是在常量区新建了一个"hello","world"以及一个"hello world",然后将"hello world"的地址赋值给str。所以如果需要对一个字符串不断的修改的话,效率是非常的低的,因为堆的好处是可以动态的增加空间,劣势就是分配新的空间消耗是很大的,比如我们看下面的测试。

public class Main {
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		String str = "";
		for (int i = 0; i < 50000; i++) {
			str += " ";
		}
		long end = System.currentTimeMillis();
		System.out.println("the run time is " + (end - start) + " ms");
	}
}

运行的结果为:the run time is 809 ms。

StringBuffer

StringBuffer是一个线程安全的,就是多线程访问的可靠保证,最重要的是他是可变的,也就是说我们要操作一个经常变化的字符串,可以使用这个类,基本的方法就是append和insert方法,StringBuffer对象的创建只能使用new而不能使用StringBuffer sb = "";这种形式,也不能使用sb += "";而需要调用append去添加到尾部。

还是上一个例子:

public class Main {
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < 50000; i++) {
			sb.append(" ");
		}
		long end = System.currentTimeMillis();
		System.out.println("the run time is " + (end - start) + " ms");
	}
}

运行结果为:the run time is 11 ms.

StringBuilder

前面说StringBuffer是线程同步的,那么很多情况下,我们只是使用一个线程,那个同步势必带来一个效率的问题,StringBuilder就是StringBuffer的非线程同步的版本,二者的方法差不多,只是一个线程安全(适用于多线程)一个没有线程安全(适用于单线程)。

 其实看了一下jdk源代码就会发现,StringBuffer就是在各个方法上加上了关键字syncronized。

参考链接:leeon

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注