简体   繁体   English

Java,这是一个Deep副本吗?

[英]Java, is this a Deep copy?

I cant seem to get a clear precise answer by reading any of the similar questions, I'm trying to deep Clone an object in Java using a copy constructor is this a 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;
         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;
    }
}

Then when I create my tile map I could do something like this 然后,当我创建我的瓷砖地图时,我可以做这样的事情

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

If i were to render both tiles at their respective locations would that work? 如果我要在各自的位置渲染两块瓷砖那会有用吗? or was the assignment tileList.get(1).setNewLocation(0,64); 或者是赋值tileList.get(1).setNewLocation(0,64); effecting like a reference and all of them have the same location as the last assignment. 影响像引用,所有这些都与上次分配的位置相同。

is this a deep copy ? 这是一份深刻的副本吗?

No, it's not because this.sprite = copyTile.sprite; 不,这不是因为this.sprite = copyTile.sprite; both objects of Tile is refering to same object of Image . Tile两个对象都是指Image同一个对象。

If i were to render both tiles at their respective locations would that work? 如果我要在各自的位置渲染两块瓷砖那会有用吗? or was the assignment tileList.get(1).setNewLocation(0,64); 或者是赋值tileList.get(1).setNewLocation(0,64); effecting like a reference and all of them have the same location as the last assignment. 影响像引用,所有这些都与上次分配的位置相同。

No, the values of x and y are independent in the two objects of Tiles and code should work and both the objects will have different x and y values. 不,x和y的值在Tiles的两个对象中是独立的,并且代码应该起作用,并且两个对象将具有不同的x和y值。

First, lets review the differences between a deep and a shallow copy. 首先,让我们回顾一下深拷贝和浅拷贝之间的差异。

A shallow copy points to the same references as the source. 浅拷贝指向与源相同的引用。 So if make a copy of instance A named B any changes to fields containing objects in B will modify these fields in A since they are pointing to the same reference. 因此,如果制作名为B的实例A的副本,对包含B中对象的字段的任何更改都将修改A这些字段,因为它们指向相同的引用。

A deep copy has independent fields/references, it does not point to the source's references. 深层副本具有独立的字段/引用,它不指向源的引用。 A change to a field/property on the copy will not impact the source's fields/properties. 对副本上的字段/属性的更改不会影响源的字段/属性。

In your case, I believe you have made a shallow copy since your assigning the reference of sprite field from the source to the copy's sprite field. 在你的情况下,我相信你已经做了一个浅的副本,因为你将精灵字段的引用从源指定给副本的精灵字段。

To illustrate this, I have modified the Tile classes source to expose the Image and have mocked an Image class. 为了说明这一点,我修改了Tile类源以公开Image并模拟了一个Image类。

Modifications for Proof of Concept 概念证明的修改

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

Proof of Concept 概念证明

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
}

Notice how changing the copied instance's sprite property affects the original instances sprite property. 注意如何更改复制实例的sprite属性会影响原始实例sprite属性。

No, this is not a deep copy as the same Image object is shared between all object of Tile. 不,这不是深拷贝,因为在Tile的所有对象之间共享相同的Image对象。

Looking at your example though it appears that this copy would be sufficient for your needs as it allows you to reuse the same Image object on different locations (which presumably is more efficient). 看看你的例子虽然看起来这个副本足以满足你的需要,因为它允许你在不同的位置重复使用相同的Image对象(这可能更有效)。

In java there are two data types: 在java中有两种数据类型:

  • primitives (float, int , double, boolean ...) which doesn't have concept of deep/shallow copying because they work with assignments. 原语(float,int,double,boolean ...)没有深/浅复制的概念,因为它们与赋值一起使用。
  • objects where a shallow copy means passing the reference. 浅拷贝意味着传递引用的对象。 while a deep copy means having a new object with the same values that the source has. 深度复制意味着拥有一个与源具有相同值的新对象。

giving the above your code doesn't satisfy deep copying when passing the Image object. 在传递Image对象时,给出上面的代码不满足深度复制。 and if you are rendering using that object then that object can only have one position. 如果使用该对象进行渲染,则该对象只能有一个位置。 which will cause your code to render both tiles at the same place. 这将导致您的代码在同一个地方呈现两个图块。

To fix this you should clone your Image object. 要解决此问题,您应该克隆Image对象。

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

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

If a method returns a reference to an internal mutable object, then client code may modify the internal state of the instance. 如果方法返回对内部可变对象的引用,则客户端代码可以修改实例的内部状态。 Unless the intention is to share state, copy mutable objects and return the copy. 除非意图共享状态,否则复制可变对象并返回副本。

So you'd have to actually make a new instance out of Image . 所以你必须用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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM