我似乎无法通过阅读任何类似的问题得到明确的答案,我正在尝试使用复制构造函数深入克隆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);影响像引用,所有这些都与上一次分配的位置相同。
答案 0 :(得分:11)
这是一份深刻的副本吗?
不,这不是因为this.sprite = copyTile.sprite;
Tile
的两个对象都引用Image
的同一个对象。
如果我要在各自的位置渲染两块瓷砖那会有用吗?或者是赋值tileList.get(1).setNewLocation(0,64);影响像引用,所有这些都与上一次分配的位置相同。
不,x和y的值在Tiles
的两个对象中是独立的,代码应该有效,并且两个对象都有不同的x和y值。
答案 1 :(得分:4)
首先,让我们回顾一下深拷贝和浅拷贝之间的差异。
浅表副本指向与源相同的引用。因此,如果制作名为A
的实例B
的副本,则对B
中包含对象的字段所做的任何更改都将修改A
中的这些字段,因为它们指向相同的引用。< / p>
深层副本具有独立的字段/引用,它不指向源的引用。对副本上的字段/属性的更改不会影响源的字段/属性。
在你的情况下,我相信你已经制作了一份浅色的副本,因为你将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属性。
答案 2 :(得分:3)
不,这不是深拷贝,因为在Tile的所有对象之间共享相同的Image对象。
看看你的例子虽然看起来这个副本足以满足你的需要,因为它允许你在不同的位置重复使用相同的Image对象(这可能更有效)。
答案 3 :(得分:2)
在java中有两种数据类型:
在传递Image
对象时,给出上面的代码不满足深度复制。
如果使用该对象进行渲染,则该对象只能有一个位置。这将导致您的代码在同一个地方呈现两个图块。
要解决此问题,您应该克隆Image
对象。
public Tile(Tile copyTile){
this.sprite = copyTile.sprite.clone();
this.x = copyTile.x;
this.y = copyTile.y;
}
答案 4 :(得分: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;
}