String.java
1.为什么String是final class?
目前结论:首先,final是为了不能让类继承。而不能继承是为了维护String是一个constant,具有immutable的性质。一旦创建,它就不可以被修改。具体见4
2.实验证明String是一个constant
理解重点:将变量a,p和String本身,如"apple"看成三个不同的东西。a,p是在stack上的引用/变量。"apple"根据初始化的不同在heap或者constant pool中
- 实验1,注意对比指针(变量)a和p的关系
String a = "apple";
String p = a;
System.out.println(a == p); // true
p = "pear";
System.out.println(a == p); // false
- 实验2,注意观察指针a地址的改变
String a = "apple"; // byte[5]@946
String p = a; // byte[5]@946
System.out.println(a == p); // true
a += "red "; // byte[9]@961
System.out.println(a == p); // false
- 实验3,注意观察String a和StringBuffer p内容的改变
public static void main(String[] args) {
String a = "apple"; // byte[5]@946
append(a);
System.out.println(a); // apple
StringBuffer p = new StringBuffer("apple");
appendBuffer(p);
System.out.println(p); // green apple
}
public static String append(String s) {
return "red " + s;
}
public static void appendBuffer(StringBuffer p) {
p.insert(0, "green ");
}
因为String immutable的性质,在进行+
操作时会新创建一个对象,在loop中使用string会特别慢。所以一般使用StringBuilder或者StringBuffer。
todo : String的回收
3.String不同的初始化方式
- 在Heap中初始化,ab指向地址不同
String a = new String("object");
String b = new String("object");
System.out.println(a == b);// stored in heap, return false
System.out.println(a.intern() == b.intern());// stored in constant pool, return true
- 在constant pool(method area)中初始化,ab指向一个字符串
String a = "constant";
String b = "constant";
System.out.println(a == b);// stored in constant pool, return true
System.out.println(a.intern() == b.intern());// exactly return true
4.如果String可以被继承
这是一个新创建一个不带final
的MyString
类,然后使用FuckMyString
子类继承,最后改变MyString值的故事
class MyString {
private final byte[] values;
public MyString(byte[] bytes) {
values = bytes;
}
public byte[] toArray() {
return this.values;
}
public void getContent() {
for (byte b : values) {
System.out.print(b);
}
}
}
public class FuckMyString extends MyString {
private final byte[] someValues;
public FuckMyString(byte[] bytes) {
super(bytes);
someValues = bytes;
}
public static void main(String[] args) {
FuckMyString dummy = new FuckMyString(new byte[]{'a', 'b', 'c'});
MyString string = dummy;
dummy.getContent(); // 979899
// change the byte array that both pointer "values" and "someValues" pointed to
dummy.someValues[0] = 'b';
dummy.getContent(); // 989899
System.out.println();
// Finally we change the value in MyString
string.getContent(); // 989899
}
}
根本原因是因为private final byte[] values;
中的final仅仅是保持values地址不变,而不能保证其中的值不变。