Java中按值而非按引用克隆自定义对象的方法及问题排查
一、原代码(未使用clone)的异常原因
你的第一段代码必然会出现行为异常,根本原因是你没有真正实现「按值复制」,而是做了引用赋值:
Element element1=firstPoint;
这行代码并没有创建一个新的Element对象,只是让element1和firstPoint指向内存中的同一个对象实例。当你执行element1.setY(firstPoint.getY()+1);时,你其实直接修改了firstPoint本身的y值!
后续的element2、element3在计算坐标时,使用的firstPoint.getY()已经是被修改后的值,而不是最初的原始值。这种依赖被篡改的初始值进行计算的逻辑,会导致最终生成的坐标完全不符合预期——至于为什么「时而正常时而异常」,完全取决于firstPoint在进入这个方法前的初始状态,刚好某次修改后的值碰巧让逻辑走通了,但这只是偶然。
二、使用clone方法的代码问题检查
你的第二段代码尝试用clone()来实现对象复制,但要让这段代码正确运行,有几个关键前提和细节需要注意:
1. Element类必须正确实现克隆能力
Java的clone()方法默认是浅拷贝,但需要类满足两个条件才能正常使用:
- 实现
Cloneable标记接口(否则调用clone()会抛出CloneNotSupportedException) - 重写
clone()方法(虽然Object类有这个方法,但它是protected的,需要改为public)
你的Element类目前没有实现这些,所以直接调用firstPoint.clone()会编译报错或者运行时抛出异常。正确的Element类应该修改为:
public class Element implements Cloneable { int x; int y; public Element(){ } public int getX() { return x; } public int getY() { return y; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } @Override public Element clone() { try { return (Element) super.clone(); } catch (CloneNotSupportedException e) { // 因为我们实现了Cloneable,所以这个异常不会发生 throw new AssertionError(); } } }
2. 代码中存在冗余的赋值操作
在克隆后的代码里,你做了这样的操作:
Element element1=firstPoint.clone(); element1.setX(firstPoint.getX()); element1.setY((firstPoint.getY()));
这两行setX/setY完全是多余的——因为clone()已经复制了firstPoint当前的x和y值,你马上又把它设置回原值,等于白做了这一步,可以直接删掉。
3. 逻辑上的合理性
排除上述问题后,这段克隆后的代码逻辑是正确的:通过clone()创建了全新的Element实例,修改这些新实例的属性不会影响原有的firstPoint、secoundPoint等对象,后续的坐标计算都会基于原始的初始值,不会出现篡改的问题。
如果你的detectTurnRightWallColision仍然有问题,那大概率和克隆无关,需要检查该方法的逻辑,或者确认克隆后的对象坐标是否符合预期(可以加日志打印每个element的x/y值来排查)。
内容的提问来源于stack exchange,提问作者user11315601

