能否创建一个包含可变对象的不可变对象?
在Java中,不可变对象是指一旦创建后,其状态(即对象的属性)不能被改变的对象。常见的不可变对象的例子是String
类。不可变对象的主要优点是线程安全和简化的程序设计。
然而,创建一个包含可变对象的不可变对象是可能的,但需要特别小心。不可变对象的设计原则是确保其内部状态在对象创建后不被改变。如果不可变对象内部包含可变对象,那么这些可变对象的状态可能会被外部代码修改,从而破坏不可变对象的特性。
下面是一个示例,展示了如何创建一个包含可变对象的不可变对象,并讨论其潜在问题。
首先,我们定义一个可变对象,例如一个简单的Point
类:
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
}
接下来,我们定义一个不可变对象ImmutableShape
,它包含一个Point
对象:
public final class ImmutableShape {
private final Point point;
public ImmutableShape(Point point) {
// 这里直接引用了可变对象
this.point = point;
}
public Point getPoint() {
// 返回可变对象的引用,可能会导致外部修改
return point;
}
}
现在我们可以创建一个ImmutableShape
对象,并尝试修改其内部的Point
对象:
public class Main {
public static void main(String[] args) {
Point point = new Point(1, 2);
ImmutableShape shape = new ImmutableShape(point);
System.out.println("Original Point: (" + shape.getPoint().getX() + ", " + shape.getPoint().getY() + ")");
// 修改可变对象的状态
point.setX(3);
point.setY(4);
System.out.println("Modified Point: (" + shape.getPoint().getX() + ", " + shape.getPoint().getY() + ")");
}
}
运行上述代码,输出将是:
Original Point: (1, 2)
Modified Point: (3, 4)
如上所示,虽然ImmutableShape
是不可变的,但由于它持有一个可变的Point
对象的引用,外部代码可以修改Point
的状态,从而影响ImmutableShape
的表现。
为了确保不可变对象的真正不可变性,我们可以在构造函数中创建Point
对象的副本,而不是直接引用它。可以通过以下方式实现:
public final class ImmutableShape {
private final Point point;
public ImmutableShape(Point point) {
// 创建可变对象的副本
this.point = new Point(point.getX(), point.getY());
}
public Point getPoint() {
// 返回一个新的副本,防止外部修改
return new Point(point.getX(), point.getY());
}
}