Java 代码不写getter, setter, 转化为 public, 有什么弊端?
PHP中文网
PHP中文网 2017-04-18 10:35:44
0
9
1355
PHP中文网
PHP中文网

认证0级讲师

Antworte allen(9)
小葫芦

呃,通过方法去操作其实有很多事情可以干,尤其在配合了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 交流的时候骄傲的说了出来,别人也只会嗤之以鼻:那个社区的质量并不高,都是灌水跟风的。

刘奇

每种语言的哲学不一样。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这种工具包可以很好的简化代码。

伊谢尔伦

上面的人说了这么多,都说漏了一点,方法具有多态性,属性没有多态性,此话怎么理解?比如Person为父类,Man为子类,父类和子类都有Name属性(虽然这很罕见),父类和子类中的name都为public。请看如下代码:

Person p = new Man();
p.name = "person";
Print(p.name);
Print(p.getName());

答案会输出
person
null

迷茫

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

我的理解是利弊是相对的,对于一个“小程序”来说,没有什么弊端,因为你和其它维护的人能清晰看到和把控参数值的变化,这种时候,因为你能完全把控程序的每个角落,public甚至“利大于弊”,因为没有了setter&getter,减少了不少代码量。但当程序“大“到一定规模程度的时候,是不是应该要考虑程序的可维护性呢,比如a.moneya.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, 那么它就被认为是公开的, 那就前后矛盾了, 应该使用 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();
小葫芦
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。

再或者还是不理解就记住一点:存在即合理,总有一天,在写某一段代码的时候,你会恍然大悟。

大家讲道理

简单场景可以使用public,setter和getter主要是对外界封闭作用,可以在setter和getter里面加一些统一的处理,重构也方便。

刘奇

我补充一点,隐藏可见性,settergetter方法不一定都是直接存取值,也可以加入一些处理逻辑。

Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage