【基础篇】揭开String、StringBuilder以及StringBuffer的神秘面纱

String这个类是Java中使用的最频繁的类之一,据本仔的不完全统计,这个类每月的使用量可饶地球…呃,三四五六圈,今天刚好用到了这个类,就简单的做个总结吧,让我们一起走进科学,探索神秘的String、StringBuilder以及StringBuffer的三兄弟

一、认识并了解String

想要熟悉一个类,最好的办法就是动动你的小手,点击查看这个类的实现源代码,String类的实现在\jdk1.6.0_14\src\java\lang\String.java 文件中。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence
{
    /** The value is used for character storage. */
    private final char value[];

    /** The offset is the first index of the storage that is used. */
    private final int offset;

    /** The count is the number of characters in the String. */
    private final int count;

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

所以请你告诉我上面的内容, 你看出了什么?
在这里插入图片描述
真相(永远)只有一个しんじつbai)はdu いつも ひとつzhi

1.从这我们可以得出,String底层是一个final类型的字符数组,所以String的值是不可变的也即意味着String类不能被继承,并且它的成员方法都默认为final方法,所以说String是个字符串常量。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。

2.上面列举出了String类中所有的成员属性,从上面可以看出String类其实是通过char数组来保存字符串的。

下面再继续看String类的一些方法实现:

public String substring(int beginIndex, int endIndex) {
	if (beginIndex < 0) {
	    throw new StringIndexOutOfBoundsException(beginIndex);
	}
	if (endIndex > count) {
	    throw new StringIndexOutOfBoundsException(endIndex);
	}
	if (beginIndex > endIndex) {
	    throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
	}
	return ((beginIndex == 0) && (endIndex == count)) ? this :
	    new String(offset + beginIndex, endIndex - beginIndex, value);
    }

 public String concat(String str) {
	int otherLen = str.length();
	if (otherLen == 0) {
	    return this;
	}
	char buf[] = new char[count + otherLen];
	getChars(0, count, buf, 0);
	str.getChars(0, otherLen, buf, count);
	return new String(0, count + otherLen, buf);
    }

 public String replace(char oldChar, char newChar) {
	if (oldChar != newChar) {
	    int len = count;
	    int i = -1;
	    char[] val = value; /* avoid getfield opcode */
	    int off = offset;   /* avoid getfield opcode */

	    while (++i < len) {
		if (val[off + i] == oldChar) {
		    break;
		}
	    }
	    if (i < len) {
		char buf[] = new char[len];
		for (int j = 0 ; j < i ; j++) {
		    buf[j] = val[off+j];
		}
		while (i < len) {
		    char c = val[off + i];
		    buf[i] = (c == oldChar) ? newChar : c;
		    i++;
		}
		return new String(0, len, buf);
	    }
	}
	return this;

从上面的三个方法可以看出,无论是sub操、concat还是replace操作都不是在原有的字符串上进行的,而是重新生成了一个新的字符串对象。也就是说:每次对String的操作都会生成新的String对象,造成内存浪费
 
所以总结下来一点:
  “对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象”。
  
二、String、StringBuffer以及StringBuilder的区别

1.简单来说,String是不可变对象,创建后便无法修改。修改实际是将引用指向了新的对象。而StringBuffer(和StringBuilder)是可变对象,他的内部有一个缓冲区,所以可以追加元素。查看源码我们可以看到:String的+ 都是通过调用StringBuilder的append()方法实现的,Java中"+"连接字符串对象时,会创建一个StringBuilder()对象并调用append()方法将数据拼接,最后调用toString()方法返回拼接好的字符串

在这里,不得不说 StringBuilder 是一个牛逼的对象,String 对象底层是使用了
StringBuilder 对象的 append 方法进行字符串拼接的

在这里插入图片描述
2.遇到字符串处理优先考虑使用String。在实际开发中只有频繁修改内容才考虑使用StringBuffer类或StringBuilder类操作。查看源码你会发现,在StringBuffer类中定义的方法全部使用“synchronized”进行同步定义,属于安全的线程操作;而StringBuilder类没有同步定义,StringBuilder类的方法都是异步方法,属于非安全线程操作。

3.未完待续…

三、String与StringBuffer的互相转换

1.将String转换为StringBuffer类对象

方式一:利用StringBuffer类的构造方法(public StringBuffer(String str))。接收String类对象,可以将String类对象实例化为StringBuffer类对象。

方式二:利用StringBuffer类中的append()方法(public StringBuffer append(String str))。利用append()方法像StringBuffer类中增加了一个String类对象,这样就相当于将String类对象转换为StringBuffer类对象。

2.将StringBuffer转换为String类对象

方式一:利用toString()方法可以将StringBuffer转换为String类对象实际上所有的类都会继承Object类的toString方法,所以所有的类对象都可以转换为String类对象。

方法二:利用String类的构造方法(public String(StringBuffer buffer))实现StringBuffer类与String类的转换。

睡了睡了~~~预知后事如何,且听下回熬夜

猜你喜欢

转载自blog.csdn.net/weixin_42777004/article/details/107052393