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

时间:2014-03-22 18:26:08

标签: 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 `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;
...
}

我将点实例变量的state更改为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())
}

当我致电Test test = new Test(1); test.pq[0].copy(point);时,我仍然遇到同样的问题

1 个答案:

答案 0 :(得分: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());
    }
}

当然,如果你的测试有一个列表或点数组,并且如果你可以从外面访问数组或点列表,你不能保证任何东西。这就是为什么每次修改都应该通过一个测试方法(这就是封装的全部内容):

    public void addPoint(Point p) {
        pointList.add(new Point(p.getState());
    }