一、 final修飾變量
- final修改基本資料類型,則基本資料類型的值不能修改
- final修改引用類型變量,則該引用不能修改,但是該變量可以修改。
public class Test4 {
public static void main(String[] args) {
final int a = ;
// a = 20; 編譯錯誤
final Test t = new Test("d",);
// t44 = new Test(); 編譯錯誤
System.out.println("修改前name:"+t.getName());
//可以修改對象的内部成員的值
t.setName("c");
System.out.println("修改後name:"+t.getName());
}
}
public class Test {
private String name;
private int age;
public Test() {
}
public Test(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
修改前name:d
修改後name:c
二、不可變對象
我們經常聽到這樣一句話“String 對象不可以修改”,這到底是什麼意思呢?
先來看下不可變對象的定義:
不可變對象是指一個對象的狀态在對象被建立之後就不再變化。不可變對象對于緩存是非常好的選擇,因為你不需要擔心它的值會被更改。
建立一個不可變類:
- 将類聲明為final,是以它不能被繼承;
- 将所有的成員聲明為私有的,這樣就不允許直接通路這些成員;
- 對變量不要提供setter方法;
- 将所有可變的成員聲明為final,這樣隻能對它們指派一次;
- 通過構造器初始化所有成員,進行深拷貝(deep copy);
- 在getter方法中,不要直接傳回對象本身,而是克隆對象,并傳回對象的拷貝;
如果構造器傳入的對象直接指派給成員變量,還是可以通過對傳入對象的修改進而導緻改變内部變量的值。例如:
public final class ImmutableDemo {
private final int[] myArray;
public ImmutableDemo(int[] array) {
this.myArray = array; // wrong
}
}
這種方式不能保證不可變性,myArray和array指向同一塊記憶體位址,使用者可以在ImmutableDemo之外通過修改array對象的值來改變myArray内部的值。
為了保證内部的值不被修改,可以采用深度copy來建立一個新記憶體儲存傳入的值。正确做法:
public final class MyImmutableDemo {
private final int[] myArray;
public MyImmutableDemo(int[] array) {
this.myArray = array.clone();
}
}
三、String對象的不可性
看下String部分源代碼
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
....
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length); // deep copy操作
}
...
public char[] toCharArray() {
// Cannot use Arrays.copyOf because of class initialization order issues
char result[] = new char[value.length];
System.arraycopy(value, , result, , value.length);
return result;
}
...
}
如上代碼所示,可以觀察到以下設計細節:
- String類被final修飾,不可繼承
- string内部所有成員都設定為私有變量
- 不存在value的setter
- 并将value和offset設定為final。
- 當傳入可變數組value[]時,進行copy而不是直接将value[]複制給内部變量.
- 擷取value時不是直接傳回對象引用,而是傳回對象的copy.
- 這都符合上面總結的不變類型的特性,也保證了String類型是不可變的類。
四、String對象是否正的不可變
其實可以通過反射機制,改變其值。
public class Test {
public static void main(String[] args) throws Exception {
String s="0123456789";
System.out.println("改變前:s=" + s);
Field f = s.getClass().getDeclaredField("value");
f.setAccessible(true);
f.set(s, new char[]{'a', 'b', 'c'});
System.out.println("改變後:s=" + s);
}
}
參考文章:
http://www.cnblogs.com/jaylon/p/5721571.html
http://www.cnblogs.com/wcyBlog/p/4073725.html
http://blog.csdn.net/z69183787/article/details/44085031