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

5 回答 5

11

这是深拷贝吗?

不,这不是因为 的this.sprite = copyTile.sprite;两个对象Tile都引用 的同一个对象Image

如果我要在各自的位置渲染两个图块,那会起作用吗?或者是分配 tileList.get(1).setNewLocation(0,64); 像参考一样影响,并且它们都与最后一个分配具有相同的位置。

不,x 和 y 的值在 的两个对象中是独立的,Tiles并且代码应该可以工作,并且两个对象将具有不同的 x 和 y 值。

于 2013-03-25T09:02:15.427 回答
4

首先,让我们回顾一下深拷贝和浅拷贝之间的区别。

浅拷贝指向与源相同的引用。因此,如果复制一个A名为实例的副本,B对包含对象的字段进行任何更改B都会修改这些字段,A因为它们指向相同的引用。

深层副本具有独立的字段/引用,它不指向源的引用。对副本上的字段/属性的更改不会影响源的字段/属性。

在你的情况下,我相信你已经做了一个浅拷贝,因为你将 sprite 字段的引用从源分配给了副本的 sprite 字段。

为了说明这一点,我修改了Tile类源以公开Image并模拟了一个Image类。

概念证明的修改

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

概念证明

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
}

请注意更改复制实例的 sprite 属性如何影响原始实例的 sprite 属性。

于 2013-03-25T09:10:43.040 回答
3

在java中有两种数据类型:

  • 没有深/浅复制概念的原语(float、int、double、boolean ...),因为它们与分配一起使用。
  • 浅拷贝意味着传递引用的对象。而深拷贝意味着拥有一个与源具有相同值的新对象。

Image在传递对象时,给出上面的代码不满足深度复制。如果您使用该对象进行渲染,则该对象只能有一个位置。这将导致您的代码在同一位置呈现两个图块。

要解决此问题,您应该克隆您的Image对象。

 public Tile(Tile copyTile){
     this.sprite = copyTile.sprite.clone();
     this.x = copyTile.x;
     this.y = copyTile.y;
}
于 2013-03-25T09:05:26.253 回答
3

不,这不是深拷贝,因为相同的 Image 对象在 Tile 的所有对象之间共享。

查看您的示例,尽管此副本似乎足以满足您的需求,因为它允许您在不同位置重用相同的 Image 对象(这可能更有效)。

于 2013-03-25T09:05:41.667 回答
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;
}
于 2013-03-25T09:06:05.273 回答