2013-03-25 73 views
7

我似乎無法閱讀任何類似的問題得到明確確切的答案,我使用的是拷貝構造函數試圖深克隆Java中的對象,這是一個深刻的副本:爪哇,這是一個深層複製?

public class Tile{ 
    Image sprite = null; 
    int x = 0; 
    int y = 0; 
    public Tile(Image setImage, int sX, int sY){ 
     this.sprite = setImage; 
     this.x = sX; 
     this.y = sY; 
    } 
    public Tile(Tile copyTile){ 
     this.sprite = copyTile.sprite; 
     this.x = copyTile.x; 
     this.y = copyTile.y; 
    } 
    public void setNewLocation(int sX, int sY){ 
     this.x = sX; 
     this.y = sY; 
    } 
} 

後來,當我創建我的瓷磚地圖我可以做這樣的事情

List<Tile> tileList = new List<Tile>(); 
Tile masterGrassTile = new Tile(grassImage, 0,0); 
tileList.set(0,new Tile(masterGrassTile)); 
tileList.set(1,new Tile(masterGrassTile)); 
tileList.get(0).setNewLocation(0,32); 
tileList.get(1).setNewLocation(0,64); 

如果我要在他們各自的位置呈現這兩個瓷磚,那會有用嗎?或者是作業tileList.get(1).setNewLocation(0,64);影響就像一個參考,他們都具有與最後一個作業相同的位置。

回答

4

首先,讓我們回顧一下深淺拷貝之間的區別。

淺拷貝指向與源相同的引用。因此,如果複製名爲B的實例A的副本,則包含B中的對象的字段的任何更改都將修改A中的這些字段,因爲它們指向相同的引用。

深層複製具有獨立的字段/引用,它不指向源的引用。對副本上的字段/屬性的更改不會影響源的字段/屬性。

就你而言,我相信你已經做了一個淺拷貝,因爲你將sprite字段的引用從源代碼分配給了副本的sprite字段。

爲了說明這一點,我修改了Tile類的來源以暴露Image並嘲笑了Image類。

修改爲概念證明

概念

通知
public static void main(String[] args) { 
    List<Tile> tileList = new ArrayList<Tile>(); 
    Tile masterGrassTile = new Tile(new Image("grass.png"), 0,0); 

    Tile copyTile = new Tile(masterGrassTile); 
    copyTile.getSprite().name = "water.png"; 

    System.out.println(masterGrassTile.getSprite().name); //Prints water.png 
} 

class Tile{ 
     /* Rest of Class*/ 
     //Additions 
    public Image getSprite() { 
     return sprite; 
    } 
    public void setSprite(Image sprite) { 
     this.sprite = sprite; 
    } 

} 

//Mock 
class Image{ 
    public String name; 
    public Image(String name){ 
     this.name = name; 
    } 
} 

證明如何改變複製的實例的精靈屬性會影響原來的實例精靈屬性。

+0

我已經意識到,它顯然是一個部分複製,圖像仍然是一個參考,因爲我傳遞一個對象,但int完全複製,因爲它們是原始的!使其成爲深度複製ID必須使用.clone()或新的圖像(copyImage.sprite)克隆圖像;以便它在內存中創建一個新的位置。謝謝你的迴應! – Snowdrama 2013-03-25 09:14:59

+0

@JayPC很高興我可以幫助一些,這聽起來像你的正確軌道。好問題! – 2013-03-25 09:23:17

11

這是一個深層複製?

不,這不是因爲this.sprite = copyTile.sprite;Tile兩個對象是指的的Image同一個對象。

如果我要在他們各自的位置渲染這兩個瓷磚,那麼這樣做會起作用嗎?或者是作業tileList.get(1).setNewLocation(0,64);影響就像一個參考,他們都具有與最後一個作業相同的位置。

不,x和y的值在這兩個對象中是獨立的,代碼應該可以工作,並且這兩個對象都會有不同的x和y值。

+1

我會補充說'int'字段,你沒有這個問題,因爲它們是原始數據類型 – iberbeu 2013-03-25 09:03:48

+0

好吧,所以我需要做這樣的事情: this.sprite = copyTile.sprite.copy(); – Snowdrama 2013-03-25 09:04:15

2

在java中有兩種數據類型:

  • 元(浮動,INT,雙,布爾...)不具有深/淺複製的概念,因爲它們與分配工作。
  • 淺拷貝意味着通過參考的對象。而深度複製則意味着擁有與源具有相同值的新對象。

給上述代碼在通過Image對象時不滿足深度複製。 如果您使用該對象進行渲染,那麼該對象只能有一個位置。這會導致你的代碼在同一個地方渲染兩個圖塊。

要解決這個問題,你應該克隆你的Image對象。

public Tile(Tile copyTile){ 
    this.sprite = copyTile.sprite.clone(); 
    this.x = copyTile.x; 
    this.y = copyTile.y; 
} 
+0

太棒了!謝謝!它可以被渲染多次,所以猜測我不需要像其他答案中提到的那樣完全深入地複製。但現在我知道了不同之處,我記得當我向Tile類中添加更多東西時。 – Snowdrama 2013-03-25 09:12:10

3

不,這不是一個深層副本,因爲相同的Image對象在Tile的所有對象之間共享。

看看你的例子,儘管看起來這個副本足以滿足你的需求,因爲它允許你在不同的位置重用相同的Image對象(這可能更有效)。

+0

我意識到,現在謝謝你!然後,如果我改變基礎圖像,它會改變,所有這些都很好記。 – Snowdrama 2013-03-25 09:08:33

2

http://www.oracle.com/technetwork/java/seccodeguide-139067.html#6

如果一個方法返回到內部可變對象的引用,則客戶端代碼可以修改實例的內部狀態。除非意圖是共享狀態,否則複製可變對象並返回副本。

所以你不得不從Image做一個新的實例。

public Tile(Tile copyTile){ 
    this.sprite = new Image(); 
    //Then copy the image to the newly instantiated sprite 
    this.x = copyTile.x; 
    this.y = copyTile.y; 
} 
+0

對!忘了圖像只是一個參考。 – Snowdrama 2013-03-25 09:07:31