在Java中克隆不可变对象

4
我有一个不可变对象,其中包含int类型的重量。在我的代码中,我需要更新这个重量。为了做到这一点,我需要复制该对象,并使用更新后的值设置重量。但是该对象没有clone()重写方法,而且我不知道哪种方式更好——是实现Cloneable接口还是使用clone()方法?
以下是我所拥有的类:
public class WeightedEdge implements Edge {

    private final WeightedEdgeComparator _weightedEdgeComparator;

    private final Vertex _target;

    private final int _weight;

    WeightedEdge(Bundle bundle, Vertex target, int weight) {
        _weightedEdgeComparator = new EdgeComparator(bundle.getDirection());
        _target = target;
        _weight = weight;
    }

    @Override
    public Vertex target() {
        return _target;
    }

    @Override
    public int weight() {
        return _weight;
    }

        @Override
    public int compareTo(WeightedEdge o) {
        return _EdgeComparator.compare(this, o);
    }

    @Override
    public int hashCode() {...}

    @Override
    public boolean equals(Object obj) { ... }

    @Override
    public String toString() { ... }
3个回答

4

直接返回一个带有新值的新对象怎么样:

// as mentioned by AndrewBissell, there is no reference to the bundle
// luckily, we only need the direction from the bundle :)
private final int _direction;

WeightedEdge(Bundle bundle, Vertex target, int weight) {
    this(bundle.getDirection(), target, weight);
}

WeightedEdge(int direction, Vertex target, int weight)
{
    _direction = direction;
    _weightedEdgeComparator = new EdgeComparator(_direction);
    _target = target;
    _weight = weight;

}

WeightedEdge updatedObject(int newWeight)
{
    return new WeightedEdge(_direction, _target, newWeight);
}

我认为这个问题在于WeightedEdge类在其构造函数中没有保留对_bundle的引用。 - Andrew Bissell
@AndrewBissell - 你说得对,我忽略了那个... 我会更新我的答案。 - MByD

0
与其仅仅出于实例化一个 EdgeComparator 的目的,将 Bundle 或可能的方向传递到构造函数中,不如将 EdgeComparator 作为构造函数参数,并在 WeightedEdge 上将对其克隆实例的引用存储在一个字段中。
WeightedEdge(EdgeComparator comparator, Vertex target, int weight) {
    _weightedEdgeComparator = comparator.clone();
    _target = target;
    _weight = weight;
}

然后你可以让WeightedEdge实现Cloneable,这样在构造克隆时就能提供所有必要的参数。这也使你能够将EdgeComparator实现的决策与WeightedEdge实现分离开来,这是良好的面向对象编程实践。

此外,你需要确保所有Vertex实例都是不可变的,否则通过传递一个可变的target,就有可能构造出该类的可变实例。或者,你也可以在构造函数中克隆target

如果EdgeComparator不可克隆,则除了像Binyamin Sharet的回答中所示那样提供一个接受并存储方向引用的构造函数之外,没有其他选择。


0

你可以使用另一个构造函数来克隆你的对象,并仅更新重量部分。

WeightedEdge(WeightedEdge wEdge, int weight) {
     //copy all fields of wEdge into THIS object, except weight.  
     //use int weight parameter to set the new weight
}

hth


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接