如果返回值是可变的,为什么要使用getter和setter?

ate*_*iob 18 java getter getter-setter

在C++中,私有数据成员的getter和setter非常有用,因为它能够通过const返回值控制可变性.

在Java中,如果我理解正确(如果我弄错了请纠正我),final在getter上指定不会那样.一旦调用者通过getter接收到数据成员引用,它就可以修改它,尽管它是私有的......

如果是这种情况(如果我在这里有严重的误解,请纠正我),为什么不宣布数据成员public并简化事情呢?

Joh*_*erg 25

使得immutable在java中的返回值是的问题要么返回已经immutable对象类型(如字符串)或返回一个副本非不可变对象.


示例1 - 已经是不可变对象

public String getValue() {
    return value;
}
Run Code Online (Sandbox Code Playgroud)

示例2 - 已经不可变对象的集合

public List<String> getValues() {
    return new ArrayList<String>(values);
}
Run Code Online (Sandbox Code Playgroud)

示例3 - 非不可变对象

public Complex getComplex() {
    return complex.clone();
}
Run Code Online (Sandbox Code Playgroud)

示例4 - 非不可变对象的集合

public List<Complex> getComplex() {
    List<Complex> copy = new ArrayList<Complex>(complexs.size());
    for (Complex c : complexs) 
        copy.add(c.clone());
    return copy;
}
Run Code Online (Sandbox Code Playgroud)

样本3和4是基于复杂类型实现Cloneable接口的便利性.

此外,为了避免子类重写不可变方法,您可以声明它们final.作为旁注,该builder模式通常用于构造不可变对象.

  • 非永恒的==可变的 (3认同)
  • 为什么不呢:`new ArrayList <String>(strings)`? (2认同)

Tom*_*icz 5

如果您希望您的类是不可变的(即只有final字段和getter),您必须确保返回的值也是不可变的.返回Strings和内置基元时可以免费获得,但是其他数据类型需要一些额外的步骤:

  • 使用不可变装饰器包装集合或在从getter返回之前防御性地复制它们
  • 制作的副本DateCalendar
  • 只返回不可变对象或防御clone它们.这也适用于集合中的对象.

请注意,如果您防御性地复制集合,客户端可以查看或修改副本,但这不会影响原始集合:

return new ArrayList<Foo>(foos);
Run Code Online (Sandbox Code Playgroud)

另一方面,如果您包装原始集合,客户端能够看到在创建包装器之后引入到集合的所有更改,但尝试更改包装器的内容将导致运行时异常:

return Collections.unmodifiableList(foos);
Run Code Online (Sandbox Code Playgroud)

底线是:Foo必须也是不可变的,否则集合是不可变的,但客户端代码仍然可以修改集合的成员.所以同样的规则适用于Foo.

如果是这种情况(如果我在这里有严重的误解,请纠正我),为什么不公开数据成员并简化事情呢?

因为:

  • 您可能希望在对象中存储可变数据,并且只提供数据的不可变(只读)视图(如包装集合)
  • 您可以在将来更改实现,摆脱该字段,例如动态计算值.