參考:http://blog.csdn.net/cjmiou/article/details/40816013
package shishi;
public class shishi1 {
private int a;
private String hae = " ?";
public void set() {
String a = "hea";
hae = a;
}
public static void change(shishi1 b,shishi1 c) {
// int hh = b.a;
// b.a = c.a;
// c.a = hh;
b = c;
System.out.println("a =" + b.a + " " +"b =" + c.a +" " +
b + " --- " + c );
}
public static void change(StringBuilder b,int c) {
b.append(" hello");
c += 3;
System.out.println("a = " + b + " b = " + c );
}
public void say() {
System.out.println(this.getClass()+" say"+"shishi1" + a);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
StringBuilder a = new StringBuilder("hello");
int b = 5;
String ab = "safsfsfsf";
int con = ab.length();
while( con-- >0) {
System.out.println(ab.charAt(con));
}
shishi1 a1 = new shishi1();
a1.a = 123;
shishi1 b1 = new shishi1();
b1.a = 132;
change(a1,b1);
System.out.println("a =" + a1.a + " " +"b =" + b1.a + " "
+ a1 +" "+ b1 );
change(a,b);
System.out.println("a = " + a + " b = " + b );
a1.set();
System.out.println(a1.hae);
}
}
先說結論:在方法中無法改變原參數的(交換之類的,屬于形參的值傳遞,隻會改變形參的引用指向),是以跟該類是否是final class無關,好多人說String類對象無法在方法中進行交換是因為String類是final class,答:并不是,因為Java的傳遞方式隻有值傳遞,也就是說當方法被調用時,形參中被傳遞進了原參數的值,對于String對象而言,傳進來的是堆中的字元串的位址。而形參進行交換時,隻是将形參中存的位址值交換了,與原參數無關,原參數沒變化,是以原參數中所存的位址值沒變化,依然指向原來的堆中字元串位址。
再提一下關于不可變類:
不可變類:建立該類的執行個體後,該執行個體的執行個體變量無法被改變,即不可變類,其不提供更改屬性值的方法,并使用 private final修飾該類的成員變量,private使得子類不可見,final使得不可改,一般提供一個帶參數的構造器,以便于初始化
如果需要建立自定義的不可變類,可遵守如下規則:
(1)使用private final 修飾符來修飾該類的屬性
(2)提供帶參數構造器,用于根據傳入參數來初始化類裡的屬性。
(3)僅為該類的屬性提供getter方法,不要為該類提供setter方法,因為普通方法無法修改final修飾的屬性
(4)如果有必要,重寫Object類中的hashCode和equals方法。在equals方法根據關鍵屬性來作為兩個對象相等的标準,除此之外,還應該保證兩個用equals方法判斷為相等的對象的hashCode也相等。
(5)如果該類中含有引用類型成員變量,如果該成員變量可變,則該類必須要保護該可變變量,比如不利用已有的該可變類對象,而是建立一個可變類對象,比如
public class Person{
private final Name name;//Name類可變
public Person(Name name){
this.name = new Name(name.getFirstName().name.getLastName());//重新建立一個name,保證即使傳入的參數被改變,Person依然不變,因為Person中的name變量是建立的,不同于傳入的那個,且無法從外界獲得,也就無法更改了
}
}
注意:final class不一定是不可變類!!!!final class僅僅代表不可繼承!!!!但是String,Integer等包裝類都是不可變類,他們都是final class
關于為什麼不可變類标準要聲明為 final class,就是為了禁止繼承,防止可變的子類對象向上轉型為父類對象,然後作為參數傳入了形參為父類的方法中,這樣,原本為不可變的父類設計的方法就有了漏洞,根據裡氏代換原則,子類能夠替代父類功能,不可變父類無法保證其子類是不可變類,是以幹脆禁止繼承,保證了不可變性!另一個原因,父類的方法設定成了final可以保證不會被重寫,但是子類仍然可以重載此方法,此時不可變性便被破壞了,是以一定要final class。
關于Integer,由于緩存池的存在,通過new Integer()出來的對象每次都是新的,而通過valueOf則首先檢查緩存池,若緩存池中有,則直接傳回緩存池中的那個元素。緩存池中隻有-128~127
例子如瘋狂Java講義 185頁内容,
Integer in1 = new Integer(6);
Integer in2 = new Integer(6);//新的對象,in1!=in2
Integer in3 = Integer.valueOf(6);//将6放入緩存
Integer in4 = Integer.valueOf(6);//直接從緩存中取,in4 == in3
Integer,和String由于是不可變類,是以在方法中改變他們無效,他們隻是指向了另一個對象,而不是對原對象進行改變,
等同于直接改變指向例如 b=c,是以無法改變原參數的引用,
StringBuffer和StringBuilder可以改變原參數指向的位址的存儲的值,
但是形參更改指向對于原參數沒有影響,比如:b = c;這樣對于原參數沒有任何影響,
對于自定義的類來說,與StringBuffer和StringBuilder類似,在方法中直接改變指向是無效的,比如第12行,對原參數無影響,但是改變指向位址所存的值時,是有效的,
與StringBuffer和StringBuilder一樣,比如10~12行
以上都針對形參值傳遞問題,對于set方法之類的對象調用方法,比如12~15行,48行a1.set();
其中對于對象a1的操作是對于a1本身的操作,(等同于this,隻不過省略了),可以對本對象的變量進行引用位址更改和指派