Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/313.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_Reference_Encapsulation - Fatal编程技术网

使用传递给构造函数-Java的引用是否安全

使用传递给构造函数-Java的引用是否安全,java,reference,encapsulation,Java,Reference,Encapsulation,我有以下代码: 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; }

我有以下代码:

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); 
}
这无疑将操纵三角形变量中引用的同一个“top”对象。 修复程序在三角形构造函数中执行以下操作:

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

(请记住,我在Point类中有一个复制构造函数,因此上面的三条语句都是有效的)

您可以在构造函数中克隆原始点,并对外部世界隐藏克隆。如果
已经实现了
可克隆性
,或者如果您可以自己实现,请这样使用:

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());
}

这是一个很好的问题

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

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

如果您决定,对于您的用例,整个对象图(这个对象、我的孩子和孩子的孩子等)在创建之后应该是不可变的,那么有一些方法可以确保这一点

要使不可变对象真正不可变,这里有一些很好的指导:

如果对象具有集合作为属性,则可以根据需要使用不可变或不可修改的集合:

最后,如果您确实允许可变状态,并且希望跟踪,则可以将子对象注册为观察者。

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

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

所以,要保守。特别是对于集合,这很容易做到

在面向对象编程模式下,很难避免可变性。函数式编程应该更符合不变性。你可能想看看Haskell或Scala只是为了尝一尝


如果您有一个复制构造函数,那么使用它是安全的。否则,如果point实现,您可以使用clone。

point不实现Cloneable,但我制作了一个复制构造函数,它接受一个点,并基本上基于另一个点构造一个点,这与您的第二个建议类似。是的,您完全正确,这取决于您希望应用程序如何工作。感谢您的全面回复!