getter应该返回对象实例的副本以避免副作用吗?

时间:2014-04-12 18:05:05

标签: java getter

我想获得一个类函数返回的值。

在课堂上:

public class MyClass {
   private Color color_ = new Color(0f, 0f, 0f, 1f);

   public Color getColor(){
      return this.color_;
   }
}

所以,在我的另一个班级,我打电话给

this.someOtherColorInOtherClass_=myClass.getColor();

如果在myClasscolor_发生了变化,someOtherColorInOtherClass_的颜色也会发生变化。

我认为这是因为在Java中,一切都是指针。所以基本上我的getter函数返回一个指向Color的指针,因此它们都指向相同的内存位置,从而改变了相同的变量。

在我的getter函数中,我可以做到

return new Color(this.color_);

并且一切都会正常工作,因为我现在有一个新的指针可以使用。

这个问题有更好的解决方案吗?

1 个答案:

答案 0 :(得分:3)

显然,你可以让getter返回克隆而不是更强大的解决方案......

不变性

If inside myClass the color_ changes though, the color of someOtherColorInOtherClass_ will also change.

这既是预期的行为,也是预期的行为。但在你的情况下,你很可能称之为讨厌的副作用

这是因为Color可变类,即。你可以自由地做:

Color color = new Color(r, g, b, alpha1);
...
color.setRGB(r2, g2, b2, alpha2);
...
color.setRGB(r3, g3, b3, alpha3);

因此使您的Color实例容易受到状态更改的影响。

一个反例是值得注意的String不可变。不可变性是一个很好的功能,它由许多(功能)语言强制执行,如Haskell和Scala,它简化了并发编程,并且由于其内在的缺乏而具有使状态相关事务变得简单易用的额外好处(令人讨厌的副作用

实际上,您是否已将两个类的颜色字段建模为String,即。一个不可变的类,共享同一个实例的问题在技术上是安全的(在你的情况下,是健壮的)。所以最重要的是,除非你有充分的理由不这样做,否则使你的类不可变,特别是那些作为参数的那些。具体来说,这意味着拥有丰富的构造函数,如果需要,不需要setter或私有构造函数,并尽可能使用最终字段。如果你的getter返回潜在的可变实例(例如set / lists / maps或其他对象),则返回[immutable]副本。

例如,一个简化但不可变的Color类可以读取(没有getter来避免样板):

public class Color {
    public final double r, g, b, alpha;

    public Color(double r, double g, double b, double alpha) {
        this.r = r;
        this.g = g;
        this.b = b;
        this.alpha = alpha;
    }
}

使用此Color类,任意数量的对象都可以共享相同的颜色实例而没有潜在的副作用。 HTH