搜尋

首頁  >  問答  >  主體

Java 代码不写getter, setter, 转化为 public, 有什么弊端?

PHP中文网PHP中文网2806 天前1383

全部回覆(9)我來回復

  • 高洛峰

    高洛峰2017-04-18 10:37:44

    呃,透過方法去操作其實有很多事情可以乾,尤其在配合了OO思想的情況下——類型是一個重要訊息。

    另外,這是一種標準,Java Bean就是這麼一回事,許多框架、第三方函式庫(最著名的就是Spring)的「正常運作」也依賴於此。 你可以搜尋一下「Java 帝國之Java bean」相關的文章。

    強烈反對關於Setter寫邏輯之類的答案。這樣的程式碼極具誤導性,有經驗的人都知道不可以把邏輯寫到"bean"層(一般對應Model層),起碼要寫到Service層(依照常見的三層式架構)。故此,這個情況下的Setter並不是顯得那麼重要了。綜上,答的關於Setter裡寫邏輯的,都是不正確的。

    最後評論一下那個說存在即合理的人,希望他能去好好理解一下「存在即合理」究竟是什麼意思。


    正式回應一下踩我的那些人————其中就不乏泛著說Setter裡寫邏輯的人,也有靠著「歪理邪說」來說服別人的人。

    說個故事吧,我一年前剛來社區的時候。曾經看看過一個分數比較高的大神簽名版上寫著垃圾SF! ,我注意到了他的聲望記錄(那時聲望記錄和GitHub的提交記錄有點相似,不過不是記錄1年這麼長),幾乎所有問題都被踩了一遍,很顯然——這是惡意的

    在混跡社群一年多來,我偶爾也會碰到這樣的情況。不過手段並沒有這麼惡劣,同樣,我承認我還是很菜的,對於有些問題吃不準,指不定就是誤人子弟,挨踩就挨踩吧!

    而今這個情況,是令我無法忍受的--錯了就是錯了,還要去誤導別人。如果別人面試因為這種如此初級的題敗而被篩掉,那是多麼的可惜!

    最後,我想告訴 all:

    1. 我不會因為被踩了而退出社區,即使是惡意踩。因為我還要去回答更多的問題,防止更多的新手被「可怕的初學者」誤導。同樣,為了維護社區的質量,我對極具誤導性的回答也絕不會放過。

    2. 如果不信我的話,請在面試的時候告訴面試官你常在Java Bean的Setter裡寫邏輯吧!

    3. 剛才我仔細的掃了一遍全部的答案,幸好有@kevinz 這樣的用戶在,我為他頂了一票,防止「可怕的初學者」將他摁下去。

    4. 回答+1分,跟風回答也才1分。被踩就是2分。而且這樣的答案越來越多,社群的品質就越來越差,屆時,就算你有1W的聲望,在你聊天or 交流的時候驕傲的說了出來,別人也只會嗤之以鼻:那個社群的品質不高,都是灌水跟風的。

    回覆
    0
  • 怪我咯

    怪我咯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這種工具包可以很好的簡化程式碼。

    回覆
    0
  • 伊谢尔伦

    伊谢尔伦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

    回覆
    0
  • 迷茫

    迷茫2017-04-18 10:37:44

    這個問題問得好!為什麼我們不直接把這個私有欄位變成pu​​blic,而要用麻煩的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;
            }
        }

    回覆
    0
  • 黄舟

    黄舟2017-04-18 10:37:44

    我的理解是利弊是相對的,對於一個「小程式」來說,沒有什麼弊端,因為你和其它維護的人能清晰看到和把控參數值的變化,這種時候,因為你能完全把控程序的每個角落,public甚至“利大于弊”,因为没有了setter&getter,减少了不少代码量。但当程序“大“到一定规模程度的时候,是不是应该要考虑程序的可维护性呢,比如a.moneya.getMoney(),突然有一天加入了一个a.action因子来影响money,如何保证每一个money的调用者都能知道因子影响规则,显然直接a.money就不那么可靠了。从写程序的角度来说,应该多写方法,这是我大学计算机程序课老师教我的,数据很枯燥,唯方法能让你形象地知道程序在干什么。从面向对象的角度来说,对象应该提供操作对象的方法,所以,还是方法,setter和getter就是体现了这一思想。从Java特性来说,setter和getter体现了封装特性的思想,就上面的例子,当另外一个money使用者需要调用money时,调用者本不需要知道还有一个action因子在那里,他只要getMoney()拿到正确的money就可以了,變數私有,而提供操作變數的公共方法。這時,利大於弊。才疏學淺,一家之言,理解不妥之處接受批評指正。


    補充,對於setter&getter內邏輯問題,我覺得是一個”應不應該的問題“,而不是一個”能不能的問題“,對於後者,我會說能,為什麼不能!而對於前者,得權衡利弊,當你程序邏輯、風險把控很好時,能方便到你,寫啊!那些優秀的框架不那麼寫,肯定也是利弊考量(擴展等),邏輯放在邏輯處理層,也是正常啊。

    回覆
    0
  • PHP中文网

    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();

    回覆
    0
  • 高洛峰

    高洛峰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。

    再或還是不理解就記住一點:存在即合理,總有一天,在寫某一段程式碼的時候,你會恍然大悟。

    回覆
    0
  • 大家讲道理

    大家讲道理2017-04-18 10:37:44

    簡單場景可以使用public,setter和getter主要是對外界封閉作用,可以在setter和getter裡面加一些統一的處理,重構也方便。

    回覆
    0
  • 怪我咯

    怪我咯2017-04-18 10:37:44

    我補充一點,隱藏可見性,settergetter方法不一定都是直接存取值,也可以加入一些處理邏輯。

    回覆
    0
  • 取消回覆