我看到大多数不变的POJO都是这样写的:
public class MyObject {
private final String foo;
private final int bar;
public MyObject(String foo, int bar) {
this.foo = foo;
this.bar = bar;
}
public String getFoo() {
return foo;
}
public int getBar() {
return bar;
}
}
但是我倾向于这样写它们:
public class MyObject {
public final String foo;
public final int bar;
public MyObject(String foo, int bar) {
this.foo = foo;
this.bar = bar;
}
}
请注意,引用是最终的,因此对象仍然是不可变的。它使我可以编写更少的代码,并允许较短的访问(减少5个字符:get
and ()
)。
我能看到的唯一缺点是,如果您想改变将来的实现getFoo()
方式来做一些疯狂的事情,那您就做不到。但实际上,这永远不会发生,因为对象是不可变的。您可以在实例化过程中进行验证,在实例化过程中创建不可变的防御副本(ImmutableList
例如,参见Guava的实例),并准备foo
或bar
对象以进行get
呼叫。
我有什么劣势吗?
编辑
我想我还缺少的另一个缺点是序列化库使用了以get
或开头的方法的反射is
,但这是一个非常糟糕的做法...
@TomášZato有上没有setX的方法
—
科里·肯德尔
String
,int
或MyObject
。例如,在第一个版本中,final
仅确保类中构造函数以外的其他方法不要尝试bar = 7;
。在第二个版本中,final
有必要防止消费者这样做:MyObject x = new MyObject("hi", 5); x.bar = 7;
。
好吧,“ 请注意引用是最终的,因此
—
托马什Zato
Object
仍然是不可变的。 ”会误导您-这样看来您认为任何内容final Object
都是不可变的,而事实并非如此。很抱歉对于这个误会。
如果基础值是可变的,则private + accessors道路也不会阻止它-
—
贝尼·切尔尼亚夫斯基-帕斯金,2015年
myObj.getFoo().setFrob(...)
。
final
不会使变量成为对象不变。我通常使用一种设计,final
在创建回调之前定义字段,以便回调可以访问这些字段。当然,它可以调用所有方法,包括任何setX
方法。