4

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

 1 year ago
source link: https://www.v2ex.com/t/872064
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

V2EX  ›  Java

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

  dxatgp02 · 12 小时 13 分钟前 · 6981 次点击

int max = obj.getMax();

int max = obj.max;

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

144 条回复    2022-08-11 20:19:45 +08:00
Macolor21

Macolor21      12 小时 12 分钟前 via iPhone   ❤️ 2

xxxxxiong

xxxxxiong      12 小时 10 分钟前 via Android

dxatgp02

dxatgp02      12 小时 8 分钟前

@Macolor21 只是为用而用?教条主义?
chendy

chendy      12 小时 7 分钟前   ❤️ 1

java 世界的习惯,关注抽象(能 get/set 数据)而不是实现(有对应的字段保存数据)
好处是 get/set 方法里可以放逻辑,比如校验,比如 get 到一个计算出的数据,set 里修改多个字段
缺点是写起来确实麻烦,于是有了 lombok ,还有 kotlin 这种带语法糖的
dxatgp02

dxatgp02      12 小时 7 分钟前

@xxxxxiong 同样的外部内获得 obj 这对象,用 getMax()和.max 有什么区别吗?
zed1018

zed1018      12 小时 4 分钟前

教条主义罢了,后来 kotlin 的 data class ,java 的 record 类型都放弃了 getter setter 。甚至 kotlin 把 java 里的 getter/setter 都翻译成 field 访问了。
chaleaochexist

chaleaochexist      12 小时 4 分钟前

我不是 java 程序员.
=========
spring 或者是 spring 之前 EJB 带进来的概念. 美其名曰 java bean.
liufish

liufish      12 小时 4 分钟前

@dxatgp02
getMax()里面可能加一些方法,例如如果 max 是个 obj

getMax() {
if (max == null) {
// 异常逻辑,日志啥的
}
}

按照你的需要,业务需求来弄。

直接 public 的 max 也是 ok 的其实。看你们的习惯和代码规范了。
chaleaochexist

chaleaochexist      12 小时 4 分钟前

问下楼主是不是也是非 Java 程序员?
zed1018

zed1018      12 小时 3 分钟前

即便不说后来的新东西,就是 java 里鼎鼎大名 lombok 的最主要的功能之一不就是生成这个吗。说到底就是大家都不乐意写,但是好像你不写显得就很不 pro 一样。
twofox

twofox      11 小时 59 分钟前   ❤️ 1

@dxatgp02 一个成员变量,我想在 set 的时候进行校验 /业务处理 /格式转换
那我是不是写个方法,obj.setValue()
但是总不能让别人改了随便赋值啊,得按照我的 setValue()来赋值,不然数据不对,那我设置为 private 很正常吧?
那我都设置为 private 了,你还怎么 int max = obj.getMax()?
yfugibr

yfugibr      11 小时 59 分钟前 via Android

@dxatgp02 get 和 set 可以对操作自定义,也可以分别赋予不同的权限,读写分离,限制了必须使用显式的赋值方法( set ),防止不经意的修改
zhuweiyou

zhuweiyou      11 小时 59 分钟前   ❤️ 4

getMax 里面还能写逻辑, 或者 只读.
如果你 obj.max 可能被 写入.
yule111222

yule111222      11 小时 59 分钟前

没有任何意义。。。封装不是这么用的 2333
xiangyuecn

xiangyuecn      11 小时 58 分钟前

又长又臭,所以交给编译阶段去生成这些玩意,源码里眼不见为净
Macolor21

Macolor21      11 小时 57 分钟前 via iPhone

再说一个,封装。如果还说教条主义,还是不理解,那下面:

如果你是刚入门,看 Java 编程思想。
如果已经是老手,学会自己寻找答案

JavaBean 规范本身没问题,问题只在于语言级别没有语法糖,Java 17 加了 record
Building

Building      11 小时 57 分钟前

写多了你就会发现,getter 和 setter 就是很有必要,很多语言你看到的 obj.max 也是在编译阶段帮你自动生成 getter ,当然你可以不用,但是一般语言都会有提供,有的甚至还有 willSet ,set ,didSet ,就算不提供,重复代码多了你也会自己写 getter 方法的
ligiggy

ligiggy      11 小时 57 分钟前

如果你是库作者,getter/setter 的好处是你封装的代码给别人用的时候体现的。

如果你只是自己用用,如果 ide 或者没有插件支持自动生成 getter/setter ,我觉得完全可以不用。

当然,如果你写 C#,属性是真的香惨了。
noe132

noe132      11 小时 57 分钟前 via Android   ❤️ 12

因为 java 没有像 C#的 getter/setter 只能用方法来模拟
makelove

makelove      11 小时 55 分钟前

java 没有内置属性语法,只能用 getXXX 代替,但.xxx 和.getXXX()又不一样,所以不管有没有逻辑全部无脑 getXXX,否则开始是.xxx 后加逻辑改 getXXX 就要改使用代码了,Java 的垃圾之处之一。
CodeCodeStudy

CodeCodeStudy      11 小时 54 分钟前

Java 的成员变量没有多态
nothingistrue

nothingistrue      11 小时 53 分钟前

@dxatgp02 #3 先把 public 、private 、protectce 、default/friend 这几个可见范围搞清楚再说。max 声明称 public ,就可以用你的第二种写法。只不过 public 的字段,要比繁琐的 getter/setter 不便处更大。
Macolor21

Macolor21      11 小时 53 分钟前 via iPhone

@zed1018 张嘴就来,record 可不可变啊?普通对象可不可变的啊?不可变的对象随便你怎么 public ,怎么访问成员变量,都没问题,它是 final

不要管中窥豹,井底之蛙,如果你是写 Java ,只能说你面向对象的思想都没理解。如果你不是,那只能说你工程化能力挺差
cmdOptionKana

cmdOptionKana      11 小时 52 分钟前

@noe132 真相了,最根本的原因就是设计语言时没考虑周到,后来只能用方法来模拟。
yolee599

yolee599      11 小时 51 分钟前   ❤️ 2

java 没有 getter/setter 只能这样做,去看看 C# 的 getter/setter 就感觉很优雅。
wanguorui123

wanguorui123      11 小时 50 分钟前

设计问题,就和 JAVA 泛型一样,难用
nba2k9

nba2k9      11 小时 48 分钟前   ❤️ 1

这边建议您重新设计门语言呢
CodeCodeStudy

CodeCodeStudy      11 小时 47 分钟前

class Person {
protected String name = "匿名";
public String toString() {
return name;
}
}

class Zhangsan extends Person {
protected String name = "张三";
}

Person zhangsan = new Zhangsan();
System.out.println(zhangsan);

比如这个例子,想重写 name 是达不到目的的,必须要重写 toString()
zed1018

zed1018      11 小时 46 分钟前

@Macolor21 笑死,你写 getter setter 不也是能让对象 mutable ,都是 mutable ,我为啥一定要 setter ,脱裤子放屁吗?有多少人写的对象没有 setter ?有多少 javaer 写 allargs ?可真就是张口就来呢。
dxatgp02

dxatgp02      11 小时 45 分钟前

说用 set get 补权限这种说法不感觉很怪吗?这是设计时的问题
同样的对象 public int mx; 和一个有 get set 的对象;
通过入参传到 A.class 里 只能 get 不能 set
传过入参传到 B.class 里 就又能 get 又能 set
yaphets666

yaphets666      11 小时 44 分钟前   ❤️ 1

见人说人话,见鬼说鬼话。每个语言有自己的套路
beisilu

beisilu      11 小时 42 分钟前

所以有人说一下 c#的 getter ,setter 是啥样的吗
cslive

cslive      11 小时 35 分钟前

那个只是规范,你不遵守也行,不会影响你写程序
djoiwhud

djoiwhud      11 小时 35 分钟前 via Android   ❤️ 2

我个人怀疑最主要的原因是以前没有很强的引用查找。直接访问变量的地方太多,调整的时候,改起来麻烦。

c#的 get,set 一样的冗余。现在写 c#的游戏开发者似乎很少这么写。
tulongtou

tulongtou      11 小时 34 分钟前 via iPhone

@dxatgp02 没错,就是这样
cheng6563

cheng6563      11 小时 32 分钟前

就是教条主义,只是一开始这样随便定了下,然后一些官方库都用 get/set 了,然后第三方库都改成读写 get/set 而不是读写 field 了,然后后面的代码也必须用 get/set 了。
dqzcwxb

dqzcwxb      11 小时 32 分钟前   ❤️ 5

我不理解==教条主义
iseki

iseki      11 小时 31 分钟前 via Android

用 Kotlin 吧,简单来说就是语言没有 property ,但是实际发现没 property 不行,就搞出来了手动 property 的 getter setter
lyxeno

lyxeno      11 小时 30 分钟前

用的最多的控制部分字段只读..只写 get 不写 set 方法,有些 bean 字段很多,get set 方法就显得又臭又长了。还好有 lombok
frank1256

frank1256      11 小时 28 分钟前

@dxatgp02 作用域,你写的自己的业务代码,没有问题。如果你是 spring 这样的开源框架,你就要控制好属性的作用域,例如 spring 提供给了你一个类,只给你构造方法可以修改属性,不提供 get ,set 。这样你是没有权限去改他的属性的,限制你的操作,更多的是防止人为操作导致报错。其次是,赋值属性的时候,经常需要校验参数的。如果写成 public ,就没有这些限制了。当然有些简单场景写 public 也没问题
qwertty01

qwertty01      11 小时 28 分钟前   ❤️ 1

不知道对一个十几年的老语言讨论个什么劲。
很明显就是历史遗留问题。

现在的新程序员这么厉害了嘛?啥都不了解上来直接开始扯淡。

不过新程序员连个 java17 的 record 都不知道,真是世风日下。
iseki

iseki      11 小时 28 分钟前 via Android

直接用 field 意味着没有插入逻辑的机会,内部细节被直接暴露出去了。举个例子当你用动态代理时怎么办呢,field 就无法被代理
Miy4mori

Miy4mori      11 小时 27 分钟前   ❤️ 2

钓鱼贴咋这么多人回复。。。
cedoo22

cedoo22      11 小时 27 分钟前

面向对象 3 大特征之一, 封装。java 没有‘只读’关键字,
对 pojo 来说,确实不方便,所以,有了 lombk 这玩意。
对于关系复杂对象来说,很有 必要。

动不动就抠帽子, 显得很 S *
LeegoYih

LeegoYih      11 小时 26 分钟前

这也能争起来,感觉大家工作都不太饱和
magicyao

magicyao      11 小时 25 分钟前   ❤️ 1

@beisilu 成员属性 get 和 set

1 、远古写法( C++)
public class Stduent
{
string name;

public string getName()
{
return name;
}

public void setName(string name)
{
this.name = name;
}

}

2 、中古写法

private string _Name;
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}

3 、近代写法

public string Name
{
get
{
return Name;
}
set
{
Name = value;
}
}
Lambda 写法
public string Name
{
get => Name;
set => Name = value;
}

4 、懒狗写法
public string Name{get; set;}
daimubai

daimubai      11 小时 23 分钟前

做访问控制和参数校验,以及避免误操作。从你举的例子来说有没有 get/set 是没多大意义的。
oneisall8955

oneisall8955      11 小时 22 分钟前 via Android

是的,你想咋样就咋样
wolfie

wolfie      11 小时 21 分钟前

封装、继承、多态

子类可以 override 父类的 getxxx()
TateLiao

TateLiao      11 小时 20 分钟前

1. getter/setter ,可以在里面添加其他逻辑,例如校验、错误处理等等。假设人对象,有个 age 属性,不通过 setter ,随便赋值,1000 合理吗?
2. getter/setter ,从封装上来说,使用者有必要知道对象里封装了什么吗?通过 getter 去访问,允许暴露被外部的细节不更合适吗? setter 同理
3. getter/setter ,可对字段控制访问级别。例如:get 公开,set 私有 /保护
Oktfolio

Oktfolio      11 小时 19 分钟前   ❤️ 1

Java 只是缺少了 getter setter 的语法糖
RedBeanIce

RedBeanIce      11 小时 17 分钟前

13 楼是对的
shenjinpeng

shenjinpeng      11 小时 16 分钟前

对 public 属性意义不大 , 但是你即想给别人用属性, 又不想让别人改 , 就得 private 封装一下, 提供方法给别人访问属性
Leviathann

Leviathann      11 小时 16 分钟前

@chaleaochexist 那为什么 C#和 js 都要做 get 和 set 关键字来实现这个行为但是简化一些,而不是直接暴露出去?
Leviathann

Leviathann      11 小时 14 分钟前

@magicyao 现代写法
class Student(var name)
所有的访问和赋值自动变成 getName 和 setName
wolfie

wolfie      11 小时 11 分钟前

为什么一帮 Java 0 基础的在抢答。
listenerri

listenerri      11 小时 11 分钟前

为长远计,避免以后要对成员变量做改动时,需要修改外部代码,所以干脆全用方法封装一下
dvsilch

dvsilch      11 小时 10 分钟前   ❤️ 1

getter setter 是合理的
不合理的是创建一个私有属性_property ,再用一个没有任何逻辑的 getter setter 去获取修改这个私有属性
chrisia

chrisia      11 小时 8 分钟前

getter setter 能放逻辑,没有其他意义。因为 java 一开始没有语法层面的支持,所以只能写 getter setter 这种冗余的代码。现代语言例如 kotlin 直接在语法层面提供 getter setter 。
xiao109

xiao109      11 小时 7 分钟前   ❤️ 2

我不喜欢的一律都是垃圾
Edsie

Edsie      11 小时 6 分钟前

Getter 、Setter 是标准的 Java Bean 定义写法
比如常见的 JSON 序列化,就是根据 Bean 定义进行转换的,也就是说即使没有 field 但是有个 getter 方法,也能序列化出这个字段
chrisia

chrisia      11 小时 6 分钟前

@chrisia 也就是说,多数情况下认为 getter setter 是没有处理逻辑的(事实也是如此,你很少会在对字段操作的时候塞逻辑,特别是 data class 这种对象),少数情况下用特定的 getter setter 语法去处理。
Edsie

Edsie      11 小时 3 分钟前

根本不是说,你需要写 getter setter
而是当你需要这个对象是一个 Java Bean 的时候,你就要符合 Java Bean 定义
pkoukk

pkoukk      11 小时 1 分钟前

c#的 getter 和 setter 就很优雅
可以直接使用 n1 = obj.Max ,obj.max=n1
但是如果只有 getter ,而你尝试 obj.Max=1 ,编译器会报错
sunhelter

sunhelter      10 小时 56 分钟前   ❤️ 1

大家别吵了,都来写.net
chrisia

chrisia      10 小时 55 分钟前

@chrisia 还有一点比较重要,getter setter 可以有不同的访问级别,不过还是那句话,这些都是少数情况,我认为针对少数情况做处理才是好的选择,而不是迫使所有字段都采用 getter setter 。
zzzzz001

zzzzz001      10 小时 54 分钟前

把控制权永远留给自己,大家维护多了,需求多了,业务复杂了,就知道这种好处了
yuezk

yuezk      10 小时 50 分钟前   ❤️ 1

@pkoukk #66 是,但是本质上还是要提供 setter/getter 来操作内部的字段,C# 提供了一个比较好用的词法糖。

类似的,JS 也支持 setter 和 getter ,但使用上还是和 C# 一样,直接用点操作符。
zhangchongjie

zhangchongjie      10 小时 49 分钟前   ❤️ 2

一般.set .get 的原因是变量 private ,你该问为什么对象内要有私有属性, 如果都是 public 哪还需要,建议重学,别在这丢人现眼
dxatgp02

dxatgp02      10 小时 44 分钟前

@dvsilch 就是这意思,就实体类还要写大量 set get.如果不想写用代码生成或 lombok. 不合理但不能问,问就是不喜欢不理解.
yuezk

yuezk      10 小时 40 分钟前   ❤️ 4

搬运一个 SO 的回答,如果楼主真想了解的话可以点过去看看,就不在这里重复了,而且说的还没有人家好。https://stackoverflow.com/questions/1568091/why-use-getters-and-setters-accessors

如果你觉得使用 obj.setName() 不如使用 obj.name 方便,那只是语法层面的问题,和 geter/setter 无关。比如 C# 中就使用这种点操作符,但它底层还是会调用 setter/getter 的。
fkdog

fkdog      10 小时 39 分钟前

其实 b=a.getB() / a.setB(b) 这种写法完全可以替代成 b=a.B / a.B=b
neochen13

neochen13      10 小时 37 分钟前

kotlin 可解
qq1009479218

qq1009479218      10 小时 33 分钟前

lisongeee

lisongeee      10 小时 32 分钟前   ❤️ 2

楼主的问题也可以是 java 为什么要写 99% 都用不到的 额外的 空的 一堆什么也不干的 setter/getter
shijingshijing

shijingshijing      10 小时 31 分钟前

@yolee599
@nba2k9

所以 rust 这种最优雅了,一上来就是:听我说,大家都是狗。。。
Cbdy

Cbdy      10 小时 28 分钟前 via Android

可以作为方法引用,另一方面,方便调试
lancelock

lancelock      10 小时 27 分钟前

你可以学学其他语言,尤其是比较新的一些,看看对这部分的处理。多看多用多比较自然就知道各种语言特性的用意在哪里
freefcw

freefcw      10 小时 25 分钟前

getter 和 setter 只是细节,关键的思想在于封装,至于用 gotter 还是 sotter,还是省略前缀,都是实现的细节

换句话说盖个房子要不要外墙上瓷砖,不上瓷砖当然也可以住人,你要觉得罗嗦花钱,那就是你的事情,但你要说瓷砖没用,那就是你的认知问题了,毕竟窑洞也可以住人,盖房子做啥
skinny

skinny      10 小时 15 分钟前   ❤️ 4

getter 和 setter 作用都不理解的(这不是 Java 特有的),我只能说在红利期程序员这碗饭太好吃了,不过看互联网公司这裁员势头,红利期也差不多过了,你不被优化谁被优化
yaphets666

yaphets666      10 小时 14 分钟前   ❤️ 1

@skinny 被优化的都是和领导关系不好的,和技术没关系
dxatgp02

dxatgp02      10 小时 8 分钟前

能回答问题的寥寥无几,人浮于事却不少.
lovedoing

lovedoing      10 小时 7 分钟前

建议使用 groovy 全局 public [狗头]
meteor957

meteor957      9 小时 58 分钟前

@skinny 你说话感觉好恶心啊,你现实生活中也这样么
devswork

devswork      9 小时 58 分钟前

int gender = -1; //-1 未定义,1 男,2 女

getGender(){
return this.gender;
}

getGenderReadable(){
if(this.gender == -1){
return "未定义";
}
if(this.gender == 1){
return "男";
}
if(this.gender == 2){
return "女";
}
return "未知";
}

setGender(int g){
if(g == 1 || g == 2){
this.gender = g;
}else{
// 非法的值,需要异常处理...
}
}

至少我这种非法值的判断、可读性的返回值,我写一次代码就够了,就不用在调用方各种 if else 判断了,且后期修改的时候(比如又加入了个“中性”),只需要改动这一处,而不需要处处改动
Kasumi20

Kasumi20      9 小时 55 分钟前

所以 Kotlin 好用啊,不关注这个东西就用默认的,需要的时候才去定义
devswork

devswork      9 小时 55 分钟前

#87 还忘了一句:我不希望这个性别 gender 被别人乱改,而我却不知道改成了什么样子,所以我只对外暴露 getter setter ,防止他们乱改( private int gender ),别人只能通过我定义的 getter setter 来修改值,这些值必定是合法的才能修改成功,也必定是我知道的,因为调用了我写的 getter setter 。
devswork

devswork      9 小时 50 分钟前

我怀疑是不是来赚金币的!!!!!!!
justNoBody

justNoBody      9 小时 42 分钟前

我觉得这个问题很有意思。我从一开始写 Java 就一直是保持这个习惯,确实没有去思考过为什么要这么写。
我查了一些资料:
- https://javarevisited.blogspot.com/2012/03/private-in-java-why-should-you-always.html#axzz7bcbsXwnO
- https://www.quora.com/Why-do-we-use-get-and-set-methods-to-access-variables-in-java-instead-of-using-them-directly
- https://www.infoworld.com/article/2073723/why-getter-and-setter-methods-are-evil.html?page=2
- https://www.freecodecamp.org/news/java-getters-and-setters/

在我看来,使用 set 和 get 方法的好处有以下几点:

1. 字段的读写权限可以更细化,如一个字段仅允许同包下的其他类去写,但是读是 public
2. 可以在 set 方法中增加一些字段的约束判断,比如 set null 时候,修改为 0 等,或者是 get null 时候,返回一个“-“的字符等等

落地到实际开发,第一点我并没有看到过有人这么用,基本上 set 和 get 方法都是 public

我也同意大家说的 get 和 set 方法可能只是缺少了一个语法糖,因为我也有用 lombok 去减少这部分的代码量

除此此外,我认为这应该是 Java 的一个规范,或者是最佳实践,因为在很多框架做反射的时候,都不约而同的用到了 set 方法。比如 jackson 的反序列化。

但是我并没有找到相关的文档,不知道在 Java 的历史进程中,这到底是如何演变出来的,这一点我非常好奇,如果有知道的朋友请艾特我,感谢。
javaisthebest

javaisthebest      9 小时 42 分钟前

@dxatgp02 😓也没见你对于别人回答的见解和疑问啊
@TateLiao 这个人的答案你回答下?
dcsuibian

dcsuibian      9 小时 34 分钟前 via Android   ❤️ 1

js 、python 、C#也有 Getter/Setter ,只是写法更像变量
楼主问的是“Java 对象里为什么要 get set”,而不是“Java 为什么要采用目前 Getter Setter 的显示写法”
dxatgp02

dxatgp02      9 小时 30 分钟前

@javaisthebest 业务逻辑是必须要包装有些还要通过事务来保障,但写大量无用 set get,再用 lombok 来折中.不奇怪吗?
那种语言告诉我们没有业务逻辑,只用语法就可以解决.业务逻辑必须包装,但不要包装的东西强行包装,就很怪.
hez2010

hez2010      9 小时 26 分钟前 via Android

尽管 class 中可能确实不需要 getter/setter 这种东西,但是如果你将多个有同样行为的类型抽象成一个 interface 的时候,就需要 getter 和 setter 了,因为 interface 不能定义字段,它解决了 C++多继承 /菱形继承带来的字段覆盖问题的。
sunmker

sunmker      9 小时 17 分钟前

面向对象:封装、继承、多态
git00ll

git00ll      9 小时 16 分钟前

obj 如果是代理类,这两个就有区别了
zmal

zmal      9 小时 11 分钟前

op 好奇的可能是为什么纯数据实体也要用 getter/setter ,这要从 Java 的一切皆对象说起了,涉及到当时的语言设计思想,略过不表。

本质上是因为在 Java 中没有结构体这种纯数据实体结构,jdk17 的 record 也只是对象的语法糖。结构体可能在 jdk18 或 19 加入。
glfpes

glfpes      9 小时 10 分钟前

语法糖,我不认为是好的设计
少打 2 个字真的不会让你早几分钟下班。反而读各种不同风格的代码会让你晚几分钟下班。
luhe

luhe      9 小时 10 分钟前 via iPhone   ❤️ 1

还是看看远处的业务逻辑吧家人们

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK