在Java中,将引用传递给构造函数工作是否安全可行?

4

我有以下代码:

public class Triangle {

    private Point left;
    private Point right;
    private Point top;

    public Triangle(Point left, Point right, Point top) {
        this.left = left;
        this.right = right;
        this.top = top;
    }

    // more program logic...
}

我在想,构建这样一个对象是否安全可靠,因为我担心 Point 类型的三个变量可能会被外部修改(破坏封装性)。例如:

public static void main(String[] args) {

    Point left = new Point(0.0, 1.0);
    Point right = new Point(2.4, 3.2);
    Point top = new Point(5.8, 2.0);

    Triangle t = new Triangle(left, right, top);

    top.setX(10.2);
    top.setY(23.4); 
}

这无疑会操作与Triangle变量中引用的同一“top”对象。因此,修复方法是在Triangle构造函数内执行以下操作:

public Triangle(Point left, Point right, Point top) {
    this.left = new Point(left);
    this.right = new Point(right);
    this.top = new Point(top);
}

请记住,Point类中有一个复制构造函数,因此上述三个语句是有效的。

3个回答

4

你可以在构造函数中克隆原始点,并将克隆点隐藏起来,如果Point已经实现了Cloneable或者你可以自己实现它,就可以这样使用:

public Triangle(Point left, Point right, Point top) {
    this.left = left.clone();
    this.right = right.clone();
    this.top = top.clone();
}

如果 Point 没有实现 Cloneable 接口,且你无法访问其源代码,那么只能手动克隆点:

public Triangle(Point left, Point right, Point top) {
    this.left = new Point(left.getX(), left.getY());
    this.right = new Point(right.getX(), right.getY());
    this.top = new Point(top.getX(), top.getY());
}

Point类没有实现Cloneable接口,但我已经创建了一个复制构造函数,它接受一个Point对象,并基本上根据另一个对象构造一个新的Point对象,类似于你第二个建议的方式。 - Mr. Nicky

3

这是一个非常好的问题。

拥有可变状态并不总是一件坏事。例如,您可以将此三角形对象实例发送到显示程序中,如果更改了点坐标,它可以在屏幕上动画显示三角形。

这取决于用例和它所应该解决的问题。

如果您已经确定对于您的用例,一旦创建了整个对象图(该对象,我的子项和子项的子项等),就应该使其不可变,那么有方法可以确保这一点。

要使不可变对象真正不可变,可以参考这里的一些指南: http://www.javapractices.com/topic/TopicAction.do?Id=29

如果对象具有集合属性,则可以根据需要使用Immutable或Unmodifiable集合: Java Immutable Collections

最后,如果您允许可变状态,并希望跟踪,请向子对象注册为观察者。 When should we use Observer and Observable

同样,原则是尽可能少地保留可变状态。换句话说,尽可能使对象不可变。不可变集合易于获得并易于使用。问题在于我们的自定义类。

如果使您的自定义对象/模型对象完全不可变,可能会出现需要复制整个对象图以更改单个属性的情况。

因此,请保守处理。特别是对于集合,这很容易做到。

在面向对象编程范 paradigm 中,很难避免可变性。函数式编程应该更加符合不可变性。您可能想要尝试 Haskell 或 Scala 以了解一下。

https://softwareengineering.stackexchange.com/questions/232711/complete-immutability-and-object-oriented-programming


是的,你绝对是正确的,这取决于你想让你的应用程序如何工作。感谢你详尽的回答! - Mr. Nicky

1
如果您有一个复制构造函数,那么使用它是安全的。否则,如果指针实现了cloneable,则可以使用克隆。

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