Java,这是深度复制吗?

Java,这是深度复制吗?,java,deep-copy,Java,Deep Copy,通过阅读任何类似的问题,我似乎都无法得到一个清晰准确的答案,我正在尝试使用复制构造函数在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;

通过阅读任何类似的问题,我似乎都无法得到一个清晰准确的答案,我正在尝试使用复制构造函数在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);
List tileList=new List();
瓷砖masterGrassTile=新瓷砖(grassImage,0,0);
瓷砖列表设置(0,新瓷砖(主瓷砖));
瓷砖列表设置(1,新瓷砖(主瓷砖));
tileList.get(0).setNewLocation(0,32);
tileList.get(1).setNewLocation(0,64);
如果我在它们各自的位置渲染这两个瓷砖,这会起作用吗?或者是赋值tileList.get(1).setNewLocation(0,64);它们就像一个引用,并且它们都与上一个赋值具有相同的位置

这是深度复制吗

不,这不是因为
this.sprite=copyTile.sprite磁贴的两个对象都引用了图像的同一个对象

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;
}
如果我在它们各自的位置渲染这两个瓷砖,这会起作用吗?或者是赋值tileList.get(1).setNewLocation(0,64);它们就像一个引用,并且它们都与上一个赋值具有相同的位置


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

在java中,有两种数据类型:

  • 原语(float、int、double、boolean…)没有深度/浅层复制的概念,因为它们处理赋值
  • 对象,其中浅复制意味着传递引用。而深度复制意味着拥有一个与源具有相同值的新对象
在传递
图像
对象时,给出上述代码不能满足深度复制。 如果使用该对象进行渲染,则该对象只能有一个位置。这将导致代码在同一位置渲染两个平铺

要解决此问题,您应该克隆
图像
对象

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

不,这不是深度复制,因为同一图像对象在平铺的所有对象之间共享

看一下您的示例,虽然看起来此副本足以满足您的需要,因为它允许您在不同的位置重用相同的图像对象(这可能更有效)。

如果方法返回对内部可变对象的引用,则客户端代码可能会修改实例的内部状态。除非目的是共享状态,否则复制可变对象并返回副本

因此,您必须实际使用
图像
创建一个新实例

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

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

浅复制指向与源相同的引用。因此,如果复制名为
B
的实例
a
,对
B
中包含对象的字段所做的任何更改都将修改
a
中的这些字段,因为它们指向相同的引用

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

在你的例子中,我相信你已经做了一个浅拷贝,因为你把源中的精灵场的引用分配给了拷贝的精灵场

为了说明这一点,我修改了
Tile
classes源代码以公开
图像
,并模拟了
图像

概念验证修改

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
}
概念验证

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
}
publicstaticvoidmain(字符串[]args){
List tileList=new ArrayList();
瓷砖masterGrassTile=新瓷砖(新图像(“grass.png”),0,0;
瓷砖复制瓷砖=新瓷砖(主瓷砖);
copyTile.getSprite().name=“water.png”;
System.out.println(masterGrassTile.getSprite().name);//Prints water.png
}

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

我会在
int
字段中添加这一点,因为它们是原始数据类型,所以我需要执行以下操作:this.sprite=copyTile.sprite.copy();正确的!忘了这张图片只是一个参考。我现在意识到了,谢谢!然后,如果我改变了基础图像,那么所有这些图像都会改变,让人记住。太棒了!非常感谢。它可以被渲染多次,所以我想我不必像其他答案中提到的那样完全深度复制。但现在我知道了区别,我记得当我向Tile类添加更多内容时,我意识到它显然是一个部分副本,Image仍然是一个引用,因为我传递了一个对象,而int是完全复制的,因为它们是原语!要使其成为深度副本id,必须使用.clone()或新映像(copyImage.sprite)克隆映像;这样它就在内存中创建了一个新的位置。谢谢你的回复@JayPC很高兴我能帮上点忙,听起来你已经走上正轨了。好问题!