java中String、StringBuffer与StringBuilder

昨天遇到一道编程题关于字符串中字符内容的替换,题目如下:
  请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
public class Solution {
    public String replaceSpace(StringBuffer str) {
    	//添加代码
    }
}

  于是想通过此题对java中字符串的定义与处理方式有所了解。

一、String

   java中没有内置的字符串类型,在标准java类库中预定义类字符串类,所有用双引号表示的都是String类的一个实例。在String类中定义了字符型数组value用于存储字符串。源码如下:

private final char value[];
...
public String() {
        this.value = new char[0];
}  
  该value数组被定义成final型,在String类众多构造函数的最简洁创建字符串对象方法中可以看到,即为存储字符串数组value初始化,且长度为0。  定义成final型的字符数组value因此也具有独特性质:final成员变量表示常量,只能被赋值一次,赋值后值不再改变。而数组作为一种特殊的变量类型(引用类型),其在内存中由栈内存中的数组变量名指向存储于堆内存中的数组值。堆内存的特性之一包括默认值初始化操作,int型默认初始化值为0,char型默认初始化值为‘ ‘。也就是说,字符串一旦创建对象后,其值即不可改变。
String str = "xuwenping";
str = str + "123";

  上面两行代码,表面看上去String str 与变量无意义,其值可以更改。其实际在代码层的操作是:第一行是在栈内存中创建字符串的引用变量str,在堆内存中创建字符串"xuwenping",("xuwenping"字符串实际以字符数组形式存储),且str作为字符串指针指向"xuwenping"的首地址(数组的首地址)。第二行则是在堆内存中创建了新的字符串"xuwenping123",将str指向新的字符串的值。而原有的"xuwenping"字符串则无人引用,将会被JVM垃圾回收。 

  如上所述,可知字符串的值不可变。若变,则是创建新的字符串。创建过程不可避免的效率低下,当然,java设计者实现了另外一种字符串对象赋值方式以希望消除效率低下的问题:字符串共享池(缓冲池)。缓冲池是java为了节省内存空间,会在内存中创建一个专门为String设计的缓冲池,用来保存已经存在的字符串,若2个字符串是一样的,则使用池中的字符串,不再创建新的对象。

		String str1 = "abc";
		String str2 = "abc";
		System.out.println(str1==str2); //true

		String str3 =new String ("abc");
		String str4 =new String ("abc");
		System.out.println(str3==str4); // false

  String str = "hello";
  上面这种方式会创建一个"hello"字符串,而且JVM的字符缓存池还会缓存这个字符串。
  String str = new String("hello");
  此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o 

二、StringBuffer

  由于字符串的变化会导致创建新的字符串效率低下,java提供了可变的字符串类StringBuffer。StringBuffer继承AbstractStringBuilder类。其默认初始化操作如下:

    public StringBuilder() {
        super(16);
    }

...
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

    char[] value;

  StringBuffer初始化调用父类构造方法,父类有一非final成员变量char[ ] value,默认创建长度为16的字符数组。当随着字符数增加,StringBuffer会自动增大,查看源码发现,其调用父类的expandCapacity方法并调用java.util.Arrays数组工具类中的copyOf方法创建新的大小为value.length * 2 + 2的数组,并将原有数组字符复制值新数组中。从而实现了字符串的随意改变。

void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
    }

三、StringBuilder

  从java1.5开始,StringBuilder开始出现,API文档如下描述:”该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)“。此句包含两层意思:一是其具有StringBuffer的特性:可随着存储字符串元素的增加而扩容;二是StringBuffer是多线程同步的,而StringBuilder是多线程不同步的。

  查看源码,并由StringBuilder的寻找过程:append ->AbstractStringBuilder.append ->ensureCapacityInternal -> expandCapacity ->Arrays.copyOf,发现两者均是调用父类的expandCapacity方法并调用java.util.Arrays数组工具类中的copyOf方法创建新的大小为value.length * 2 + 2的数组,并将原有数组字符复制值新数组中从而实现扩容性质。

  而在多线程方面,查看源码可知StringBuffer除了构造器外其他方法均以synchronized实现锁同步,而StringBuilder则始终是裸奔。在《java核心卷一:基础知识》有如下论断:在jdk5.0中引入了StringBuilder类。这个类的前身是StringBuffer,其效率稍有些低,但容许采用多线程的方式执行添加或删除字符的操作。如果所有字符串在一个单线程中编辑(通常都是这样),则应该用StringBuilder替换它。这两个类的API是相同的。

四、解答

  最后,针对引出该话题的问题予以解答:

public class Solution {
    public String replaceSpace(StringBuffer str) {
        String stri = str.toString();
        stri = stri.replaceAll(" ", "%20");
        return stri;
    }
}

  StringBuffer、StringBuilder均可以通过toString方法转换成Sting对象。

  

时间: 2024-10-18 11:34:43

java中String、StringBuffer与StringBuilder的相关文章

Java中String,StringBuffer与StringBuilder的差别

String 字符串常量: StringBuffer 字符串变量〈缓冲区〉(线程安全): StringBuilder 字符串变量〈缓冲区〉(非线程安全): 简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响

Java中string拼接,StringBuilder,StringBuffer和+

Java中string拼接,StringBuilder,StringBuffer和+,到底哪个更合适? StringBuilder线程不安全,效率较线程安全的StringBuffer高.jdk1.5之前,+操作会产生大量String对象,影响GC的效率,但是jdk1.5之后做了优化,使用+操作符不一定会产生大量String对象,而是自动优化为StringBuilder方式.如果是在一个for循环中进行String拼接,还是不建议使用+操作,因为会大量产生new StringBuilder()对象

【Java】String,StringBuffer与StringBuilder的区别??

String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以

java中String类、StringBuilder类和StringBuffer类详解

本位转载自http://www.cnblogs.com/dolphin0520/p/3778589.html 版权声明如下: 作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利 正文: 探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得

java中String&amp;StringBuffer&amp;StringBuilder

1. String,字符串常量 StringBuffer,字符串变量(线程安全) StringBuilder,字符串变量(非线程安全) 2.String and StringBuffer String和StringBuffe的主要区别在于String是不可变对象,每次对String进行改变的时候其实 等于生成了一个新的String对象,因此经常改变内容的字符串不要使用String类型,因为每次形成新的对象都会对系统的性能产生影响,特别当内存中的无引用的对象多了之后,JVM的GC就会开始工作,那速

java中string , StringBuffer , StringBuilder 区别

1.String String变量的值不能改变,如果要改变String变量的值,虚拟机首先会遍历方法区中的字符串常量,如果存在需要的值,则虚拟机直接把此常量值的地址分配给String变量,如果不存在这样的值,虚拟机则会另外在方法区中划分出一块内存空间存储字符串常量,然后把这块地址赋给String变量. 因此,String类的内容声明后不可被改变,改变的只是其内存地址的指向. 2.StringBuffer StringBuffer是使用缓冲区存储字符串对象的,对象的内容可以改变.并且是线程安全的.

java中的StringBuffer和StringBuilder

/* java.lang.StringBuffer; java.lang.StringBuilder; 1.StringBuffer和StringBuilder是什么? 是一个字符串缓冲区. 2.工作原理 预先在内存中申请一块空间,以容纳字符序列, 如果预留的空间不够用,则进行自动扩容,以 容纳更多字符序列. 3.StringBuffer,StringBuilder  和  String最大的区别? String是不可变得字符序列,存储字符串常量池中. StringBuffer底层是一个char

Java中的StringBuffer、StringBuilder和包装器类型

1.如何使用StringBuffer类? 答:1).StringBuffer类用于表示可以修改的字符串,称为字符串缓冲对象: 2).使用运算符的字符串将自动创建字符串缓冲对象: 例:str1 + str2的操作,实际上把str1与str2都创建成StringBuffer类对象: 2.StringBuffer类的构造方法有哪些常用的重载方式? 答:StringBuffer()        创建一个空的StringBuffer对象,默认保留16个字符的缓冲空间 StringBuffer(Strin

java中string,stringBuffer和StringBuider

最近学习到StringBuffer,心中有好些疑问,搜索了一些关于String,StringBuffer,StringBuilder的东西,现在整理一下. 关于这三个类在字符串处理中的位置不言而喻,那么他们到底有什么优缺点,到底什么时候该用谁呢?下面我们从以下几点说明一下 0.string是内容不可变的字符串.底层使用了不可变的字符数组(final char[]) 而StringBuffer,StringBuilder底层使用的是可变的字符数组 1.三者在执行速度方面的比较:StringBuil

Java中String, StringBuffer, StringBuilder

String: 1,是字符串常量,一旦创建就不能修改.对于已经存在了的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去. 2,String也是final类,不能被继承. 3,而且String是对象而不是基本类型. 4,string重写了equals方法和hashCode()方法. StingBuffer: 1,是字符串可变对象,可以对字符串进行操作,修改字符串原有值时不会新建一个对象. 2,执行效率较慢,但是线程安全 3,StringBuffer没有覆盖equals方法和ha