背景
我们在学教科书时,“老师”告诉我们,字段定义成private , 然后通过get,set访问,这样能屏蔽内部实现细节。
本文探讨的是 get , set 方法都存在的情况, 如果一个类的某个属性不允许修改,它只有get方法,那肯定要定义为private ,才能防止被篡改。
我对“屏蔽内部实现细节”这个理由到现在我都持怀疑的,原因如下
1) 我们绝大数对象都是POJO,get , set 没有任何逻辑
2) 我印象中也不鼓励在get 或者 set 中写一些特殊逻辑,很容易引发Bug, 举个的例子
public class User2 {
private String name;
public String getName() {
this.name = "prefix_" + this.name;
return name;
}
}
上面那一代码你们看出来问题了吗?每调用一次get方法,name就会拼接一个前缀,随着次数增多,当时团队有人就在get里面做了一些逻辑, 那个字段刚好是文章的内容,结果字段越来越长,大对象直接进入老年代,应用就频繁Full GC。
所以对屏蔽内部细节而将字段定义为private 我不赞同,因为很多情况 get ,set 不应该有什么逻辑
否则lombok 框架也不会产生了。
当然说安全,我也不认同,虽然不能直接给属性赋值,但是可以通过set 进行恶意篡改,所以说什么安全我不认同。
我认为的可能的理由如下
与JSON序列化有关
因为我们与前端数据传输基本都是以JSON 形式传输的, 而不同的序列化框架处理方式不一样,有的序列化框架的JSON 字段以 定义的属性为准,而有的框架用的是get , set 方法。还有很多中间件框架通过反射来给属性赋值, 很多框架用的也是get , set 方法。
基于这种限制,既然你都有了get , set 方法, 你在将属性定义为public ,显然有些多余(尽量提供一个方式访问和修改属性)。因此我认为这是属性定义为private 的其中一个理由。
继承有关
public 属性子类能够继承过来,但是private 属性子类不会继承过来,但是get , set 方法由于是public ,因此能够被继承。
很多中间件框架,强制需要有get , set 的理由,我认为是在存在继承关系时,反射访问父类属性更加麻烦点尤其在复杂的继承关系时,如果使用get , set 方法就简单了,不需要考虑继承问题。
get , set 方法是在接口中定义的
我截取了Spring BeanDefinition 接口定义,因此它的实现类必须要实现get , set方法,
所以对应的属性,为private ,(没必要再申明public 了,已经有访问,和修改属性的方法了)
AOP有关
因为AOP 只能对方法进行拦截,如果是简单的属性赋值,想扩展功能比较难,如记录属性被修改的日志,如果是对public 字段直接赋值的,记录日志将非常麻烦。但是如果是get ,set 方法,很轻松通过AOP 进行增强。
以上我个人理解的,不足之处还请斧正。