class Bicycle {
public int speed;
// ...
}
public class BicycleTest{
public static void main(String[] args){
Bicycle b = new Bicycle();
b.speed = 300000; //什么?自行车这么快?不科学啊?自行车车速不超过120吧。
// 可是作为程序员的我怎么办呢?只能在文档里告诉用这个类的人:超过120罚款?
// WTF!写这个类的程序员该死。
b.speed = -30; // 这个?负的速度,高中物理?我勒个去。
}
}
我们如果改成这个,是不是好点:
class Bicycle {
private int speed;
public int setSpeed(int speed) {
if(speed > 120){
this.speed = 120;
} else if(speed < 0){
this.speed = 0;
} else{
this.speed = speed;
}
}
public int getSpeed() {
return speed;
}
}
public class BicycleTest{
public static void main(String[] args){
Bicycle b = new Bicycle();
b.speed = 300000;
System.out.println(b.getSpeed()); // 显示120
}
}
呃,通过方法去操作其实有很多事情可以干,尤其在配合了OO思想的情况下——类型是一个重要信息。
另外,这是一种标准,Java Bean就是这么一回事,许多框架、第三方库(最著名的就是Spring)的“正常运作”也依赖于此。你可以搜索一下“Java 帝国之Java bean”相关的文章。
强烈反对关于Setter写逻辑之类的答案。这样的代码极具误导性,有经验的人都知道不可以把逻辑写到
"bean"
层(一般对应Model层),起码要写到Service层(按照常见的三层式架构)。故此,这个情况下的Setter并不是显得那么重要了。综上,答的关于Setter里写逻辑的,都是不正确的。最后评价一下那个说存在即合理的人,希望他能去好好理解一下“存在即合理”究竟是什么意思。
正式回应一下踩我的那些人————其中就不乏泛着说Setter里写逻辑的人,也有靠着“歪理邪说”来说服别人的人。
说个故事吧,我一年前刚来社区的时候。曾看见过一个分数比较高的大神签名版上写着垃圾SF!,我注意到了他的声望记录(那时声望记录和GitHub的提交记录有点相似,不过不是记录1年这么长),几乎所有问题都被踩了一遍,很显然——这是恶意的。
在混迹社区一年多以来,我偶尔也会碰到这样的情况。不过手段并没有这么恶劣,同样,我承认我还是很菜的,对于有些问题吃不准,指不定就是误人子弟,挨踩就挨踩吧!
而今这个情况,是令我无法忍受的——错了就是错了,还要去误导别人。如果别人面试因为这种如此初级的题失利而被筛掉,那是多么的可惜啊!
最后,我想告诉 all:
我不会因为被踩了而退出社区,哪怕是恶意踩。因为我还要去回答更多的问题,防止更多的新手被“可怕的初学者”误导。同样,为了维护社区的质量,我对极具误导性的回答也决不会放过。
如果不信我的话,请在面试的时候告诉面试官你经常在Java Bean的Setter里写逻辑吧!
刚才我仔细的扫了一遍全部的答案,幸好有@kevinz 这样的用户在,我为他顶了一票,防止“可怕的初学者”将他摁下去。
回答+1分,跟风回答也才就1分。被踩就是2分。而且这样的答案越来越多,社区的质量就越来越差,届时,就算你有1W的声望,在你聊天 or 交流的时候骄傲的说了出来,别人也只会嗤之以鼻:那个社区的质量并不高,都是灌水跟风的。
每种语言的哲学不一样。Java 讲的是完全的面向对象,在编码时提倡代码高度的灵活性与可扩展性。而像
Go
语言提倡的又是代码极致的简洁性,所以只需要像下面的方式定义struct
就ok。但是在
Java
中你还是应该遵守规范为javabean
定义get/set
方法,因为你遵守规范才来享受规范为你带来的好处,比如你接入第3方库的时候,要使用reflect
的方式来操作javabean
时他们大多数都是采用get/set
方法来实现的。如果你的javabean
此时没有get/set
方法那显然你是无法使用该库的。以个人经验感受,代码的简洁性比代码的灵活性与可扩展性要重要。所以
java
中也出现了像lombok
这种工具包可以很好的简化代码。上面的人说了这么多,都说漏了一点,方法具有多态性,属性没有多态性,此话怎么理解?比如Person为父类,Man为子类,父类和子类都有Name属性(虽然这很罕见),父类和子类中的name都为public。请看如下代码:
答案会输出
person
null
这个问题问得好!为什么我们不直接把这个私有字段变成public,而要用麻烦的setter和getter去做呢?原因有几个:
永远不要相信客户的输入
我们来假设这个类:
我们如果改成这个,是不是好点:
便于修改
假如说,现在要求speed是0-40之间。如果没有getter和setter,所有的代码要重写一下,没有1个钟头时间基本不可能完成。有了这个setter的话,简单,改一下setter的逻辑,1分钟不完工,这程序员可以开了。
我的理解是利弊是相对的,对于一个“小程序”来说,没有什么弊端,因为你和其它维护的人能清晰看到和把控参数值的变化,这种时候,因为你能完全把控程序的每个角落,
public
甚至“利大于弊”,因为没有了setter&getter
,减少了不少代码量。但当程序“大“到一定规模程度的时候,是不是应该要考虑程序的可维护性呢,比如a.money
和a.getMoney()
,突然有一天加入了一个a.action
因子来影响money
,如何保证每一个money
的调用者都能知道因子影响规则,显然直接a.money就不那么可靠
了。从写程序的角度来说,应该多写方法,这是我大学计算机程序课老师教我的,数据很枯燥,唯方法能让你形象地知道程序在干什么。从面向对象的角度来说,对象应该提供操作对象的方法,所以,还是方法,setter和getter
就是体现了这一思想。从Java特性来说,setter和getter
体现了封装特性的思想,就上面的例子,当另外一个money使用者需要调用money
时,调用者本不需要知道还有一个action因子在那里,他只要getMoney()
拿到正确的money
就可以了,变量私有,而提供操作变量的公共方法。这时,利大于弊。才疏学浅,一家之言,理解不妥之处接受批评指正。补充,对于setter&getter内逻辑问题,我觉得是一个”应不应该的问题“,而不是一个”能不能的问题“,对于后者,我会说能,为什么不能!而对于前者,得权衡利弊,当你程序逻辑、风险把控很好时,能方便到你,写啊!那些优秀的框架不那么写,肯定也是利弊考量(扩展等),逻辑放在逻辑处理层,也是正常啊。
首先method的翻译是方法。
然后我来理解一下你的困惑是
而其实你不这么做的原因主要还是因为这样做很麻烦吧。
但是实际上,你会拥有那些必须使用getter setter的域(字段,属性),比如只读的域,所以1⃣️,为了整体代码的一致性,还是全部getter setter的好。
2⃣️,使用ide的帮助其实并不用花太多功夫就可以完成。
3⃣️,这基本上算是一个规范性的东西,完全不必要思考需不需要这样做。
4⃣️,有些情况的确可以不需要getter setter的,如果你有自信这里的数据都很简单就直接public。
关于另外一个问题
首先一个私有字段可能只有getter和setter的一个,这自然算不上公开。如果setter getter都有,也不是你想象的那么简单。因为你自己写的getter setter没任何处理逻辑,但你考虑这个
如果你有像这个例子一样的需求呢,在存姓名的时候需要先去除掉多余的空格。(顺便我不敢保证上面代码语法没问题,好久没写java了。
关于开放字段调用会更舒服的问题,其实题主你提到的python的开放字段,并不是开放字段对不对。实际存储字段是_name,而getter和setter是name,这和java仅仅是语法的不同,本质是一样的。
我再放两段代码来展示一下getter和setter的好处。
再比如
这里就有一个封装和控制的问题。假设你直接访问属性 goodDog .size;突然有一天,你可能需要对每个尺寸,或者某个尺寸过滤掉一些东西,怎么办?那么你就只好在出现goodDog .size的地方到处添加过滤机制。如果你使用getSize()方法,那么我就在这个方法里面过滤一下就OK了。 其实总体思想就是一个面向对象的观点来做事情,你要什么,就给我讲,我到屋里给你拿出来,但是你却不可以直接进屋去拿,万一你不熟悉我家里的情况,把我家搞乱了咋个办啊。
如果goodDog .size=12这样直接设置的话不安全,万一size的值是小于10的话
是不是在每个属性设置的地方都要进行验证,为了不让这种事情发生,Java就统一的在set方法的时候改变值,控制范围,这样就不要以后需求变化的时候满世界的找那些地方使用了goodDog .size
有参方法和无参方法要看方法的具体用途 set方法和get方法是为了体现面向对象编程的封装思想 把成员变量设为private 只能通过特定方法修改和访问 保证了程序的安全性.
还有上面的回答,像java bean或者hibernate这些,它去属性不是取你定义的属性size,而是取你的getSize,然后去掉get方法S小写,得到size。
再或者还是不理解就记住一点:存在即合理,总有一天,在写某一段代码的时候,你会恍然大悟。
简单场景可以使用public,setter和getter主要是对外界封闭作用,可以在setter和getter里面加一些统一的处理,重构也方便。
我补充一点,隐藏可见性,
setter
和getter
方法不一定都是直接存取值,也可以加入一些处理逻辑。