首页  >  问答  >  正文

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

PHP中文网PHP中文网2712 天前1310

全部回复(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

    这个问题问得好!为什么我们不直接把这个私有字段变成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;
            }
        }

    回复
    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
  • 取消回复