Java 对象里为什么要用 get set?

2022 年 8 月 11 日
 dxatgp02

int max = obj.getMax();

int max = obj.max;

第二种写法不是更简单,更好理解?

19358 次点击
所在节点    Java
185 条回复
lux182
2022 年 8 月 11 日
@dxatgp02 不要着急盖帽子(教条主义)。
private var;//变量私有
public get/set ;//变量操作开放
这样的好处是,
1.变量作为成员私有,不允许别人随便获取和更改。
value = instance.var //获取变量 value = instance.getVar()
instance.var = value //赋值变量 instance.setVar(value)
2.面向修改关闭,面向扩展开放
java 面向对象的设计模式的基本原则。
在大型工程中,设计模式是模块化的基础。大家都遵守统一的设计模式,最终才能快速的合作开发。
如果依靠程序员的个人能力约束,没有语法层面限制,最终项目的维护是灾难性的
3.java 一直不是最激进的语言,有时候觉得好像过于啰嗦,但从工程实践来说,它是很放心的语言
dxatgp02
2022 年 8 月 11 日
如果真的思考过就回答下面的问题:
Q1 一个黑箱的实体对象 set/get 值,是否要自行通过工具类或断言类再验证?这种实体类 public set/get 和 public 字段的区别在什么地方?打断点打日志反编译工具全都上?
Q2 入参拿到一个 obj 对象后 对象 private 属性+private set() 是否就无法注入且更变 obj 里的字段值?

数据对象里大量 set/get 只有 this.v = p 或 return this.v 只是感觉这种语法及其奇怪。
Huelse
2022 年 8 月 11 日
最大的作用在于序列化,你不需要注释就知道这个类是干啥的
xylxAdai
2022 年 8 月 11 日
没啥用。最烦 get/set 。如果只是单纯的拿变量,建议还是直接 obj.value 吧
AV1
2022 年 8 月 11 日
@BigDogWang
其他语言(比如 JS )倒是挺方便的,只需把那个属性变成 getter/setter 就行了,其他地方可以继续保留 a=b.c 和 b.c=a 语法不变。
snowlyg
2022 年 8 月 11 日
存在即合理
11232as
2022 年 8 月 11 日
如果一个对象在自己的整个生命周期可以不对自身状态做任何限制,那写 getter 、setter 确实没啥意义,全部的属性设置成 public 也没啥问题。但稍微大一点的程序里面的对象或多或少都得对属性的访问域作出限制,setter 和 getter 是其中限制访问的一种方法之一。简单讲就是为了封装。
举个简单的例子,有一个日历对象保存了一个 List<Schedule>,它对外暴露的方法可能就是一个`publlic void addSchedule(String date,ScheduleType type,String description)`,一个`public List<Schedule> getSchedule()`,而且 getter 返回的这个 List<Schedule>还是一个不可变对象——你不能不通过日历对象就去更改代办事项列表,这样可能会跳过很多校验,比方说同一个时间点不能有两个代办事项。
而且日历对象不能每次都让客户端程序直接生成一个 Schedule 插入到 List 中,Schedule 可能还需要保存用户的信息,日历对象可以通过添加依赖资源来在 add 方法中解决这个问题,而不是需要客户端程序每次重复输入一遍用户的信息。客户端只需要提供时间、类型和描述。
getter 和 setter 有它存在的意义,但和其他很多好东西一样,一旦滥用就令人生厌。最后,如果你真不喜欢 getter 和 setter ,而又得在 Java 生态里干活,那我推荐学习一下 kotlin ,它在语法层面支持自动的 getter 和 setter 。
shalk
2022 年 8 月 11 日
具体情况具体分析,有的时候,你用方法二是可以的。
有的时候并不是,有一些框架会和 get set 配合。
因此,能写一,就不写二。因为不好写,就由了 lombok ,或者 插件生成 等等方法解决这个问题。
msg7086
2022 年 8 月 12 日
是不是先明确一下你问的到底是「用 getter/setter vs 字段」还是「写 getter/setter 代码 vs 不写 getter/setter 代码」?

我随便拿 Ruby 来举个例子。Ruby 里 obj.var = value 实际会调用 setter 方法 obj.var=(),obj.var 实际会调用 getter 方法 obj.var(),而获取 field 如果不走 getter/setter 则只能通过反射。

所以 Ruby 是一个典型的,用 getter/setter 但是不需要你手写 getter/setter 方法代码的语言。

现在你这个问题有些歧义,看上去像是在问为什么要用 getter/setter ,但是却又好像在抱怨需要手写 getter/setter 而不是语言自动生成。
msg7086
2022 年 8 月 12 日
至于通常用 getter/setter 而不是直接读写 field 的理由是,代码可控性。

字段是一个数据。读取和写入数据的是代码。那么这个代码,谁有最终控制权?

如果一个类只包含数据,并且有另一个你能控制的类来操作这个数据,那么这个数据类就不需要 getter/setter 。操作数据的类就充当了 getter/setter 的作用,因为这个类也是属于你全权控制的。
但是如果是交给第三方调用的类就不行了。当你要修改一个行为的时候,你需要一个一个组去协调,让别人按照你的意思去改他们的调用方法才行。

又比如你调试 bug 的时候需要监控谁在什么时候修改了你类里面的一个字段。如果有 setter ,你把日志或者断点插进去即可。没有 setter 的话,你去哪里找调用方呢。

还有一个点,就是 getter/setter 是方法,而方法是可以重载的。子类行为可以和父类不同。比如同样存储数据,父类可以存在字段里,子类可以重写然后存进数据库里。

顺便一提,上面很多人都说 C#的 property 好用。Property 就是字段+getter+setter 的语法糖,归根结底还是 getter/setter 设计方案。
coala
2022 年 8 月 12 日
目前来说, 如果你不按这套规范写, 用轮子会出很多问题, 转 Json, 序列化, 对象拷贝之类的情况, 所以必须按规范写。

要知道这些值都是 private 修饰的,不能外部直接访问, 所以有了 getter/setter ,

应该问为什么非要用 private 修饰? 如果是为了访问控制, 为什么非要访问控制? 安全在哪里?
BigDogWang
2022 年 8 月 12 日
@DOLLOR 是的,所以说不同语言不同的设计。我用 java 使用封装就是为了防止后面出现这种情况。后面用 kt 就没有这种顾虑。都是工作经验换来的呀
Anarchy
2022 年 8 月 12 日
看 kotlin 的特性就行了,kotlin 就是少写了很多 java 的模板代码
Akitora
2022 年 8 月 12 日
getter 和 setter 可以被动态代理,一些 orm 以此实现的懒加载功能
wolfie
2022 年 8 月 12 日
@guoqiao
二极管思维,设计模式不适合套用世界上 100% 的事务设计,所以不改用设计模式。
只会情绪输出有点自主思考吧。
karloku
2022 年 8 月 12 日
好处是让接口更有稳定性.

用了 getter/setter, 日后无论你怎么改里面的实现方式, 只要保持行为一致, 使用者都不需要更新自己的代码. 如果直接 obj.value 的话, 日后如果要更改内部实现逻辑, 下游用着要炸.
yigedala
2022 年 8 月 12 日
java 诞生于 90 年代,而且也是从 C++发展出来的,由于时代的局限性,没有类似于 js 中对象 property 的特性。
就算后面想加,也会因为代码兼容性而作罢了,这也是不断的开发新的编程语言的原因。
guoqiao
2022 年 8 月 12 日
@BigDogWang

"我就想问你。一开始你觉得不需要访问控制,然后到处直接访问变量。突然有一天,这个属性需要访问控制了,你改起来蛋疼不。。。不同语言本身就有不同的设计和风格"

不蛋疼, 如下:

```
# V1: no access control
class Person:
def __init__(self, name):
self.name = name

# V2: make name readonly
class Person:
def __init__(self, name):
self._name = name

@property
def name(self):
return self._name

@name.setter
def name(self, value):
raise AttributeError("name is readonly")


# no change to interface & usage:
p = Person("Foo Bar")
print(p.name)
# work with V1, Exception for V2:
p.name = "John Smith"

```
guoqiao
2022 年 8 月 12 日
@karloku 并不会, 如上.
liuzhihang
2022 年 8 月 12 日
试着把自己的系统全部改成 public 和 static 你看看大家开发用的怎么样。

就比如我问我四川朋友,为什么川菜要加辣椒,不加又不是不能吃。或者直接吃碳水不也一样,为啥要各种烹饪。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://v2ex.ih06.com/t/872064

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX