天天看點

java對象引用-要掌握的細節

hello ,好久沒來了。

今天我來和大家分享一下有關引用變量的注意事項,一是加深一下自己的了解,二是對這塊不太了解的同學可以看看。

大神可飄過,有什麼不對或不足的地方請多多指教,謝謝。

假設場景:

有一個統計遊戲玩家資訊調查問卷系統,玩家填寫了調查問卷,會給玩家一些獎勵,當然目前這不是我們關注的部分。

我們需要記錄一下玩家的姓名,年齡,郵箱,以及玩家曾經玩過的遊戲有哪些。

既然要記錄玩家玩過的遊戲,必然要有Game類:

package indi.bruce.summary;

public class Game {
    
    private int id;   //随便填寫一個id
    private String name; //總要有個遊戲名字吧
    private String developer;  //遊戲是誰開發的
    private String type;   //遊戲總要有個類型吧 ,例如:政策,體育,動作等等
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDeveloper() {
        return developer;
    }
    public void setDeveloper(String developer) {
        this.developer = developer;
    }
    
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    
    
}      

現在定義玩家類 Player:

package indi.bruce.summary;

import java.util.ArrayList;
import java.util.List;

public class Player {
    
    private int id ;  //玩家編号
    private String name;  //姓名
    private int age;  //年齡
    private  String email;  //郵箱
    
    private List<Game> gameList;  //曾經玩過的遊戲,便于分析使用者行為

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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;
    }

    public List<Game> getGameList() {
        if(gameList == null){
            return new ArrayList<Game>();
        }
        return gameList;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}      

正題開始:

假設場景1:玩家問卷資料已經存庫,玩家要修改自己的資訊,而系統需要記錄一下到底修改了哪些地方。  

      1)從資料庫讀取使用者的資料Player。

      2)将原來的對象player複制出來一份給temp對象,玩家修改資訊在temp對象上修改(既然要記錄玩家修改了什麼,則需要原來的對象和現在的對象對比)。

      3)兩個對象做一下對比,就可以做操作記錄了。

場景1測試代碼:

@Test
public void sceneOne(){
  Player player = getPlayer(1110);  //從資料庫擷取的對象
  System.out.println("print player.getName() is:"+player.getName()); 

  Player temp = player;  //玩家修改資訊全部在副本temp上操作,這樣就可以對比到底玩家修改了什麼資訊,哈哈哈....
  temp.setName("moon");  //玩家修改了名字
  System.out.println("print temp.getName() is:" + temp.getName());  //哈哈...成功了,多簡單的事情
  System.out.println("print player.getName() is:" + player.getName());
	
  /*但是列印結果
  * print player.getName() is:sky
  * print temp.getName() is:moon
  * print player.getName() is:moon
  * 
  * 疑問:為什麼隻是修改temp屬性name的值,而player的name值也變了呢?
      */
}

//假設該方法是從資料庫擷取該使用者的資料對象,這不是我們目前關注的部分
public Player getPlayer(int id){
  Player player = new Player();
  player.setId(1110);
  player.setName("sky");
  player.setAge(20);
  player.setEmail("[email protected]");

  return player;

}
      

  

為什麼會出現上面的情況呢,來分析一下引用變量的工作原理:

java對象引用-要掌握的細節

  1.代碼中"Player player = getPlayer(1110);"做了兩件事:

    1)将玩家1110資料從資料庫資料庫讀出來(這部分假設從資料庫讀出來),并加載的堆記憶體中(player對象實際上隻存在堆記憶體中)。

    2)建立一個引用變量player(其實就是指針)指向堆記憶體的player對象(也就是記錄堆記憶體中player的記憶體位址)

  2.代碼"Player temp = player;"做了一件事:

    建立引用變量temp,并且指向堆記憶體中的player對象。

  總結:是以不管是針對棧中的引用變量temp,還是棧中的引用變量player操作,實際上都是操作堆記憶體中的player對象。

  注意:解決場景1出現的問題,需要引入一個概念"深拷貝",概念請問度娘.

     解決方案:1)首先Player類需要實作Cloneable接口:public class Player implements Cloneable 

          2)需要在Player中重寫Object的clone方法

                public Object clone(){

                  Object obj = null;
                   try {
                       return super.clone();
                   } catch (CloneNotSupportedException e) {
                        e.printStackTrace();
                   }
                   return obj;
             }      

          3)在調用的地方:Player player = getPlayer(1110); Player temp = (Player)player.clone();