https://www.cnblogs.com/dolphin0520/p/3592498.htmlhtml
https://zwmf.iteye.com/blog/1738574java
https://www.cnblogs.com/aspirant/p/10320652.html程序員
https://www.zhihu.com/question/31203609編程
對象
、對象引用
對象
與對象引用
對象
首先咱們應該明白
對象
與對象引用
不是一回事。數組
《Java編程思想》原話說:「按照通俗的說法,每一個對象都是某個類(class)的一個實例(instance),這裏,‘類’就是‘類型’的同義詞。」jvm
從這句話能夠得知:
對象
是類的實例
。好比,能夠把人類
看作類的實例
,那麼具體到某我的的張三
他就是對象
.編程語言
對象
與對象引用
再讀《Java編程思想》的一段話:「每種編程語言都有本身的數據處理方式。有些時候,程序員必須注意將要處理的數據是什麼類型。你是直接操縱元素,仍是用某種基於特殊語法的間接表示(例如C/C++裏的指針)來操做對象。全部這些在 Java 裏都獲得了簡化,一切都被視爲對象。所以,咱們可採用一種統一的語法。==儘管將一切都「看做」對象,但操縱的標識符實際是指向一個對象的「引用」(reference)。」==函數
"操縱的標識符實際是指向一個對象的「引用」(reference)"這句話明確的指出
引用
和對象
不是一回事。ui
爲了方便說明,定義一個簡單的類:this
class Person { String name; int age; }
有了這個類,就能夠用它來建立對象:
Person person1 = new Person();
一般把這條語句的動做稱之爲建立一個對象,其實,它包含了四個動做。
對象
(也簡稱爲Person對象)。引用變量
。所謂Person類引用
,就是之後能夠用來指向Person這一類對象
的對象引用
。對象引用
指向剛建立的那個Person類的對象
。爲了更加清楚瞭解原理,把Person person1 = new Person()
這條語句拆成兩部分:
Person person1;//第一句 person1 = new Person(); //第二句
爲了形象地說明對象、引用及它們之間的關係,能夠作一個或許不很穩當的比喻。
對象
比如是一隻很大的氣球,大到咱們抓不住它。引用變量
是一根繩, 能夠用來系汽球。
若是隻執行了第一條語句,還沒執行第二條,此時建立的
引用變量
person1還沒指向任何一個對象
,它的值是null.(引用變量
能夠指向某個對象
,或者爲null。)
此時的person1比如一根尚未繫上任何一個汽球的繩1。
執行了第二句後,一隻
汽球1
作出來了(new一個Person類對象),並被系在person1這根繩上。咱們抓住這根繩,就等於抓住了那隻汽球1
。
在原來的基礎上增長多幾句代碼:
Person person1;//第一句 person1 = new Person(); //第二句 Person person2; //第三句 person2 = person1; //第四句 person2 = new Person(); //第五句 person1 = person2; //第六句
執行到第三句代碼就又作了一根繩2,還沒繫上汽球。
執行第四句代碼,這裏發生了複製行爲,名爲person1的
對象引用
複製給了person2(要說明的是,對象自己並無被複制),person2也是對象引用
,至關於繩2也系在汽球1上。
執行第五句代碼,則引用變量person2改指向第二個對象,繩2系向新的汽球。
從以上敘述再推演下去,咱們能夠得到如下結論:
對象引用
能夠指向0個或1個對象
(一根繩子能夠不繫汽球,也能夠系一個汽球);對象
能夠有N個引用
指向它(能夠有N條繩子繫住一個汽球)。按上面的推斷,person1也指向了第二個
對象
。這個沒問題。問題是第一個對象
呢?沒有一條繩子繫住它,它飛了。多數書裏說,它被Java的垃圾回收機制回收了。這不確切。正確地說,它已成爲垃圾回收機制的處理對象。至於何時真正被回收,那要看垃圾回收機制的心情了。
由此看來,下面的語句應該不合法吧?至少是沒用的吧?
new Person();
它是合法的,並且可用的。譬如,若是咱們僅僅爲了打印而生成一個對象,就不須要用引用變量來繫住它。最多見的就是打印字符串:
System.out.println(「Hello World」);
字符串對象「Hello World」在打印後即被丟棄。有人把這種對象稱之爲臨時對象。
對象與引用的關係將持續到對象回收。
public class TestBasicType { //基本類型的參數傳遞 public static void testBasicType(int m) { System.out.println("m=" + m);//m=50 m = 100; System.out.println("m=" + m);//m=100 } public static void main(String[] args) { int i = 50; testBasicType(i); System.out.println("i=+"+i);//i=50 //只是將值複製給參數m,m和i是兩回事 } }
public class Person { public int age;//Person的屬性,全局變量,初始age爲0 public void addAge(){ this.age = this.age+1; } public static void changeAge(Person p){ Person p1 = p; //這裏將對象引用p複製給p1,p和p1指向同一對象,所以不管p仍是p1操縱對象,對象的內容都會改變 p1.addAge(); //p1操縱 對象發生改變,p1指向的對象的age=1 System.out.println("p1.age="+p1.age); //所以p1.age=1 } public static void main(String[] args) { Person p = new Person();//建立一個Person對象,Person p 建立一個Person類的對象引用 changeAge(p);//將引用p複製給了這個方法的形參 System.out.println("p.age="+p.age);//p和p1指向同一對象,所以p.age=1 } }
能夠將上面的p1比喻爲汽車的剎車,p比做汽車的油門,汽車的速度同時受到油門和剎車的控制,不管踩下油門仍是剎車,
車速必有變化。固然控制車速的還會有離合,能夠假設離合爲新的並指向車速的引用p2,那麼車速就由p,p1,p2控制,也就是說能夠多個引用指向一個對象。
下面咱們經過一個反例來證實值傳遞
public class CallByValue { private static User user=null; private static User stu=null; /** * 交換兩個對象 * @param x * @param y */ public static void swap(User x,User y){ User temp =x; x=y; y=temp; //只是複製了引用給了參數x,y //x,y變化影響不了外面的引用user,stu } public static void main(String[] args) { user = new User("user",26); stu = new User("stu",18); System.out.println("調用前user的值:"+user.toString()); System.out.println("調用前stu的值:"+stu.toString()); swap(user,stu); System.out.println("調用後user的值:"+user.toString()); System.out.println("調用後stu的值:"+stu.toString()); } }
調用前user的值:User [name=user, age=26] 調用前stu的值:User [name=stu, age=18] 調用後user的值:User [name=user, age=26] 調用後stu的值:User [name=stu, age=18]
即便java函數在傳遞引用數據類型時,也只是拷貝了引用的值罷了,之因此能修改引用數據是由於它們同時指向了一個對象,但這仍然是按值調用而不是引用調用。
Java中對 = 的理解很重要啊!!
=
是賦值操做
:在java中,=
是一個動做,一個能夠改變內存狀態的操做,一個能夠改變變量的符號,而+ - * /卻不會。
賦值操做
實際上是包含了兩個意思:
=
右側變量的值或引用。對於基本數據類型變量,=
操做是完整地複製了變量的值。換句話說,「=以後,你我已無關聯」.
對於非基本數據類型變量,=
操做是複製了變量的引用。
參數自己是變量,全部咱們對變量的操做、變量能有的行爲,參數都有,參數傳遞本質就是一種 =
操做。