最近忽然想起来这个很简单的东西,看到挺多很对这个存在一些疑问,我就写了这个自己的理解。主要解决string和stringbuffer有什么区别,为什么string是不可变的,stringbuffer是可变的。我通过源码层面帮助大家理解。
1.StringBuffer继承AbstractStringBuilder,char数组没有final修饰。
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
2.而StringBuffer继承了AbstarctStringBuilder,他的char数组用的是他的父类AbstarctStringBuider.
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/** use serialVersionUID from JDK 1.0.2 for interoperability */
static final long serialVersionUID = 3388685877147921107L;
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
/**
* Constructs a string buffer with no characters in it and
* the specified initial capacity.
*
* @param capacity the initial capacity.
* @exception NegativeArraySizeException if the <code>capacity</code>
* argument is less than <code>0</code>.
*/
public StringBuffer(int capacity) {
super(capacity);
}
/**
* Constructs a string buffer initialized to the contents of the
* specified string. The initial capacity of the string buffer is
* <code>16</code> plus the length of the string argument.
*
* @param str the initial contents of the buffer.
* @exception NullPointerException if <code>str</code> is <code>null</code>
*/
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
3.String用的char数组被final修饰,也就是说被构造函数赋值之后就不能再次赋值。所以,String不能再次赋值。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
<span style="color:#ff0000;">private final char value[];</span>
/** Cache the hash code for the string */
private int hash; // Default to 0
/**
* Initializes a newly created {@code String} object so that it represents
* the same sequence of characters as the argument; in other words, the
* newly created string is a copy of the argument string. Unless an
* explicit copy of {@code original} is needed, use of this constructor is
* unnecessary since Strings are immutable.
*
* @param original
* A {@code String}
*/
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
4.既然String是不可变字符串对象,如何才能改变让其可变?
通过Java中的反射机制实现。因此,前文中说到的String是不可变字符串对象只是针对“正常情况下”。而非必然。
public static void stringReflection() throws Exception {
String s = "Hello World";
System.out.println("s = " + s); //Hello World
//获取String类中的value字段
Field valueField = String.class.getDeclaredField("value");
//改变value属性的访问权限
valueField.setAccessible(true);
char[] value = (char[]) valueField.get(s);
//改变value所引用的数组中的第5个字符
value[5] = '_';
System.out.println("s = " + s); //Hello_World
}