Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
复制实例以避免更改java实例状态_Java_Object - Fatal编程技术网

复制实例以避免更改java实例状态

复制实例以避免更改java实例状态,java,object,Java,Object,假设我有一节课 public class Test{ Point[] pq = null; public Test(int Capacity) { Point[] pq = new Point[Capacity]; } public static void main(String[] args) { Point point = new Point(); // suppose it has a given state `s

假设我有一节课

public class Test{
    Point[] pq = null; 
    public Test(int Capacity) {
            Point[] pq = new Point[Capacity];
    }

    public static void main(String[] args) {
        Point point = new Point(); // suppose it has a given state `state` equal to 0
        Test test = new Test(1);
        test.pq[0] = point; // here test[0] has a `state` equal to 0
        point.state = 1 //Suppose now I change the `state` of the point instance variable to 1

    }
 ...}
public class Point{
    public Integer state = 0;
...
}
我将point实例变量的
状态更改为1
然后
test.pq[0]。state
现在等于
1
。如何防止代码出现这种行为

编辑1,在Point类中,我添加了getter和setter,并将
public Integer state
转换为
private Integer state=0
,我添加了这个

public void copy(Point point){
    this.setState(point.getState())
}

当我调用
testtest=newtest(1)时;test.pq[0].复制(点),我仍然遇到同样的问题

避免此问题的干净方法是使Point类不可变:

public final class Point
    private final int state;

    public Point(int state) {
        this.state = state;
    }

    public int getState() {
        return state;
    }
    // no setter !
}
这样,没有人可以修改点的状态,并且一切都是安全的

如果该点需要是可变的,并且您不想让调用者修改测试点的状态,那么您必须复制:

public class Test {

    private Point point; // it would be the same with an array or a list

    public class Test(Point p) {
        // defensive copy
        this.point = new Point(p.getState());
    }

    public Point getPoint() {
        // defensive copy
        return new Point(p.getState());
    }
}
当然,如果您的测试有一个点列表或点列表,并且您可以从外部访问该数组或点列表,那么您不能保证任何事情。这就是为什么每次修改都应该通过一种测试方法(这就是封装的全部内容):


使用不同的
对象。我不是下选者,但你的代码没有任何意义。测试不是数组,pq没有定义,等等,所以不可能回答。发布可编译代码。@jbnize抱歉,确实不清楚,我刚刚编辑了我的帖子。如果您将状态设置为“私有”或“受保护”,而不是“公共”,main()将无法直接更改它。(如果这就是你想要的答案,你真的需要通过一个像样的Java教程来学习。)在将对象放入数组之前克隆它?虽然我不认为您希望这样做,但是有没有一种方法可以在不声明变量
state
final的情况下做到这一点?您可以使状态不是final,但是如果目标是使对象不可变,那么不使其成为final会有什么好处?final精确地确保字段值不能更改。如果它可以改变,那么对象就不再是不可变的,您需要制作防御副本来保护自己。此外,将字段设置为final可以在多线程代码中提供更多可见性方面的保证。对不起,我对java非常陌生。如果我想从外部更改
状态
值,我可以在声明变量final时执行此操作吗?您正是问了如何避免从外部更改测试点的状态值。我的回答解释了这一点:要么你完全禁止更改状态,要么你允许更改状态,但你会制作防御副本,以确保外部更改分数副本的状态,并且不会更改测试的分数。对不起,我不想打扰你,但我编辑了我的帖子,我添加了一些
copy
方法,但我不明白为什么这次它不起作用
    public void addPoint(Point p) {
        pointList.add(new Point(p.getState());
    }