高洛峰2017-04-18 10:37:44
呃,透過方法去操作其實有很多事情可以乾,尤其在配合了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 交流的時候驕傲的說了出來,別人也只會嗤之以鼻:那個社群的品質不高,都是灌水跟風的。
怪我咯2017-04-18 10:37:44
每種語言的哲學不一樣。 Java 講的是完全的物件導向,在編碼時提倡程式碼高度的彈性與可擴充性。而像Go
语言提倡的又是代码极致的简洁性,所以只需要像下面的方式定义struct
就ok。
type S struct {
A string
B int
}
但是在Java
中你还是应该遵守规范为javabean
定义get/set
方法,因为你遵守规范才来享受规范为你带来的好处,比如你接入第3方库的时候,要使用reflect
的方式来操作javabean
时他们大多数都是采用get/set
方法来实现的。如果你的javabean
此时没有get/set
方法那顯然你是無法使用該函式庫的。
以個人經驗感受,程式碼的簡潔性比程式碼的靈活性與可擴展性重要。所以java
中也出现了像lombok
這種工具包可以很好的簡化程式碼。
伊谢尔伦2017-04-18 10:37:44
上面的人說了這麼多,都說漏了一點,方法具有多態性,屬性沒有多態性,此話怎麼理解?例如Person為父類,Man為子類,父類別和子類別都有Name屬性(雖然這很罕見),父類別和子類別中的name都為public。請看如下碼:
Person p = new Man();
p.name = "person";
Print(p.name);
Print(p.getName());
答案會輸出
person
null
迷茫2017-04-18 10:37:44
這個問題問得好!為什麼我們不直接把這個私有欄位變成public,而要用麻煩的setter和getter去做呢?原因有幾個:
我們來假設這個類別:
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
}
}
假如說,現在要求speed是0-40之間。如果沒有getter和setter,所有的程式碼要重寫一下,沒有1個鐘頭時間基本上不可能完成。有了這個setter的話,簡單,改一下setter的邏輯,1分鐘不完工,這程式設計師可以開了。
public int setSpeed(int speed) {
if(speed > 40){
this.speed = 40;
} else if(speed < 0){
this.speed = 0;
} else{
this.speed = speed;
}
}
黄舟2017-04-18 10:37:44
我的理解是利弊是相對的,對於一個「小程式」來說,沒有什麼弊端,因為你和其它維護的人能清晰看到和把控參數值的變化,這種時候,因為你能完全把控程序的每個角落,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內邏輯問題,我覺得是一個”應不應該的問題“,而不是一個”能不能的問題“,對於後者,我會說能,為什麼不能!而對於前者,得權衡利弊,當你程序邏輯、風險把控很好時,能方便到你,寫啊!那些優秀的框架不那麼寫,肯定也是利弊考量(擴展等),邏輯放在邏輯處理層,也是正常啊。
PHP中文网2017-04-18 10:37:44
首先method的翻譯是方法。
然後我來理解你的困惑是
但是真的要為以後想那麼多嗎
其實你不這麼做的原因主要還是因為這樣做很麻煩吧。
但是實際上,你會擁有那些必須使用getter setter的域(字段,屬性),例如只讀的域,所以1⃣️,為了整體程式碼的一致性,還是全部getter setter的好。
2⃣️,使用ide的幫助其實不用花太多功夫就可以完成。
3⃣️,這基本上算是規範性的東西,完全不必要思考需不需要這樣做。
4⃣️,有些情況的確可以不需要getter setter的,如果你有自信這裡的數據都很簡單就直接public。
關於另外一個問題
如果一個私有的字段提供了getter和setter, 那麼它就被認為是公開的, 那就前後矛盾了, 應該使用 public
目的是什麼
首先一個私有欄位可能只有getter和setter的一個,這自然不算是公開。如果setter getter都有,也不是你想像的那麼簡單。因為你自己寫的getter setter沒任何處理邏輯,但你考慮這個
private String name;
public void setName(String name) {
this.name = name.trim();
}
public String getName() {
return name;
}
如果你有像這個例子一樣的需求呢,在存姓名的時候需要先去除掉多餘的空格。 (順便我不敢保證上面程式碼文法沒問題,好久沒寫java了。
關於開放字段調用會更舒服的問題,其實題主你提到的python的開放字段,並不是開放字段對不對。實際儲存欄位是_name,而getter和setter是name,這和java只是語法的不同,本質是一樣的。
我再放兩段程式碼來展示getter和setter的好處。
private int userId;
public User getUser();
public void setUser(user);
再例如
private Map data;
public User getUser();
public int getStatus();
高洛峰2017-04-18 10:37:44
class GoodDog {
private int size;
public int getSize() {
return size;
}
public void setSize(int s){
size = s;
}
}
這裡就有一個封裝和控制的問題。假設你直接訪問屬性 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。
再或還是不理解就記住一點:存在即合理,總有一天,在寫某一段程式碼的時候,你會恍然大悟。
大家讲道理2017-04-18 10:37:44
簡單場景可以使用public,setter和getter主要是對外界封閉作用,可以在setter和getter裡面加一些統一的處理,重構也方便。