【问题标题】:What are the uses of getter/setters in Java? [duplicate]Java中getter/setter的用途是什么? [复制]
【发布时间】:2009-08-28 08:42:01
【问题描述】:

我见过给成员变量一个私有修饰符,然后使用 getter/setter 方法来设置和获取变量的值(以标准化的名义)。

为什么不将变量本身公开(除了依赖于 IOC 的 getter/setter 等的 spring 框架的情况)。它达到了目的。

在 C# 中,我看到了成员变量大写的 getter/setter。为什么不将变量本身公开?

【问题讨论】:

  • 考虑如果您的应用程序要扩展到多个用户/PC,在这种情况下,您必须确保访问您声明为公共的单个属性的 800 个类之间的同步。或者,更简单地说,考虑更改了某些业务逻辑,因此更改该属性不再只是更改其值,您需要对边界或其他内容进行少量检查..

标签: java coding-style


【解决方案1】:

为了从一开始就获得稳定的 API。 Java 专家认为,如果稍后,您可能希望在设置/获取实例成员时有一些额外的逻辑,您不希望通过用公共方法替换公共字段来破坏现有 API。这是Java中的主要原因。

在 C# 的情况下,由于 二进制接口兼容性,使用公共属性而不是公共字段。有人问a similar question就在这里,在SO上。

所以,这一切都是为了封装一些逻辑,同时仍然保留接口以供……未来验证。

【讨论】:

  • 我想要一些反对票的理由。我可能是错的,没关系,但我想从这整个 SO 事情中学到一些东西。我没听说要帮助别人,好吗?
  • 我对你投了反对票,因为说它是关于封装的,不要生气:) 主要原因是集成,而不是封装,因为这样做不是封装。如果底层类型发生变化,公共 API 也会受到同样的影响。如果您以真正“封装”的方式编写类,调用者将不会受到此类更改的影响。
  • 没问题丝滑,我不生气,我只对原因感兴趣,为此我感谢你。它帮助我提高自己。
【解决方案2】:

早在 2003 年,getter and setter methods are evil 就已为人所知。

【讨论】:

    【解决方案3】:

    因为接口 只允许指定方法,而不是变量。接口是 API 的基石。

    因此,要通过接口访问字段,您需要拥有 getter 和 setter。

    【讨论】:

      【解决方案4】:

      这样做是为了让您可以在发布后更改公共 API 中的 getter 或 setter 实现。使用公共字段,您将无法检查值的有效性。

      【讨论】:

        【解决方案5】:

        Encapsulation

        您还提到了 C# 属性。这些实际上只是底层的 getter/setter,但语法更简洁。

        【讨论】:

        • 不,封装不是原因。封装是关于根本不设置属性,而是针对类调用通用函数,根据需要操作属性。除了 get/set 什么都不做的 get/set 不是封装。
        • 确定是封装。关键是您可以稍后更改它以执行其他操作。
        • 我会考虑在设置器中包含验证逻辑以进行封装。与没有验证相比,拥有一个“空”设置器仍然可以在需要时轻松添加它。
        • starblue:不,你错了。那不是封装。泰勒:你也错了。这不是封装,而是关于隐藏变量的设置方式。封装永远不用担心其他类的变量。
        • 柔滑,在我看来,“隐藏变量的设置方式”的表述表示封装。好的,这不是一个非常复杂的封装,尤其是对于空的 getter/setter,但您仍然隐藏了一些东西,以便将来实现的更改不会影响接口。
        【解决方案6】:

        它是encapsulation 的一部分:从类的实现(使用实例变量)中抽象出类的接口(“getters”和“setters”)。虽然您可能决定通过直接访问实例变量今天来实现该行为,但您可能希望明天采取不同的做法。假设您需要通过网络检索值而不是将其存储在本地——如果您已经封装了行为,那么这是一个微不足道的更改。但是,如果其他对象依赖于对实例变量的直接访问,那么您将陷入困境。

        【讨论】:

          【解决方案7】:

          在 Java 中,getter 和 setter 最主要的用途是惹恼开发人员。第二个最重要的用途是用无用的噪音使代码混乱。此外,它会强制您对同一事物使用不同的名称,具体取决于您所在的位置(在课堂内或课堂外)。不要忘记增加的歧义(您是在类中调用 getter 还是直接使用该字段?)接下来,它们用于允许访问私有数据,但这只是一个次要的副作用;)

          在其他编程语言中,编译器会为您生成它们(当然,除非您提供自己的实现)。例如,在 Delphi 中,字段有 readwrite 修饰符(就像 Java 中的 privatestaticfinal)。定义是否会为您生成 getter 或 setter。

          与 Delphi 的人不同,Java 的人希望一切都是明确的。 “如果它不在源头中,它就不存在”。所以唯一的解决方案是强迫人们手动编写所有的getter和setter。更糟糕的是,人们必须为同一事物使用不同的名称。

          【讨论】:

          • Python 之禅说:“显式胜于隐式”。但这仅在 Python 这样的动态类型语言中才有意义。
          • 我真的很喜欢这个答案中的讽刺,+1。
          • @lutz:这只适用于很少使用的东西。对于你每天遇到的像 getter 和 setter 这样的东西,你可以有更复杂、更隐含的东西。
          【解决方案8】:

          getter 和 setter 很可能是有史以来最大的谎言。它们被认为是良好设计的标志,而事实恰恰相反。应该教新程序员正确的封装,而不是编写只包含 getter 和 setter 的愚蠢的数据载体类。

          (如果您想在以后更改实现,您需要 getter 和 setter 来保证您的代码的未来适用性的想法是 YAGNI 的一个明显案例。但这真的是无关紧要的。)

          【讨论】:

          • Getter 和 setter 仍然是使用适当封装的良好设计的一部分 - 只是不是所有东西都是愚蠢的 getter 和 setter。
          • 真正的问题是 getter 不会 让你的代码适应未来。它们使得在不破坏客户端类的情况下更改属性类型变得更加困难。在这方面,getter 比 setter 差得多。
          【解决方案9】:

          最常见的原因是对封装的理解不足。当开发人员认为封装东西真的只是意味着 getter 和 setter 而不是封装行为时。

          拥有 getter/setter 的正当理由是:

          1) 您正在制作一个通用¹ 对象,例如 JComponent。通过使用 getter/setter 而不是直接访问变量意味着您可以首先对所述变量进行一些预处理(例如验证它是否具有设定范围)或更改底层实现(从 int 切换到 BigInteger无需更改公共 API)。

          2) 您的 DI 框架不支持 ctor 注入。通过只有一个设置器,您可以确保变量只设置一次。

          3) (与#1 相关)允许工具 与您的对象进行交互。通过使用这样一个简单的约定,GUI 工具可以轻松获取给定组件的所有设置。 NetBeans 中的 UI 构建器就是一个例子。

          ¹ 非通用类型。我知道用不好的词,请提出替代方案。

          【讨论】:

            【解决方案10】:

            拥有一个setter可以让你

            • 执行验证
            • 如果新值与之前的值不同,则触发属性更改事件

            在所讨论的情况下,如果只是读取或写入值,则不需要 getter 和 setter。

            【讨论】:

            • +1 用于触发属性更改事件。
            【解决方案11】:

            嗯,

            OOP。 ;)

            或者更准确一点:

            Getter 和 Setter 用于为类提供已定义的接口 特性。检查 OOP 链接,它更详细地描述了这些概念......

            K

            【讨论】:

              【解决方案12】:

              如果有限制,您需要封装这些属性,例如进行一般有效性检查或发布更改事件等。基本用途是对“外部世界”隐藏属性。

              【讨论】:

                【解决方案13】:

                一些 Java 框架需要它们(我认为是 JavaBeans)。

                -- 编辑

                一些海报试图说这是关于封装的。不是。

                封装就是隐藏对象的实现细节,只暴露相关的功能。

                提供一个除了设置一个值之外什么都不做的get/set根本不能做到这一点,唯一的原因是:

                • 在设置/获取之前执行一些额外的验证
                • 从其他地方获取变量
                • 与框架集成 (EJB)

                【讨论】:

                • 这是关于稍后封装,同时仍然保留接口。
                • 实际上,如果你重新阅读这个问题,它是关于封装的:“我见过给成员变量一个私有修饰符,然后使用 getter/setter 方法来设置和获取变量的值(以标准化的名义)。为什么不让变量本身公开呢?答案是:封装。
                • 好的,我对继续这个争论不感兴趣。我已经在 cmets 中就这个主题提出了自己的观点,我认为它们就足够了。我确实建议那些认为这是封装的人实际上做一些研究。因为你错了。
                【解决方案14】:

                有几个原因:

                • 一些 Java API 依赖于它们(例如 Servlet API);
                • 公开非最终变量被认为是一种不好的风格;
                • 进一步的代码支持:如果将来某个时候您需要在变量的每次访问/变异(获取/设置)之前执行一些操作,那么您遇到的问题就会减少。 在像

                  这样的 C# 结构中

                  公共整数年龄 { 得到 { 返回 (int)(今天() - m_BirthDate); } }

                are 只是语法糖。

                【讨论】:

                  【解决方案15】:

                  属性思想是 OOP(面向对象编程)的核心。但问题是 Java 不是在语言核心(语法 / JVM)中引入它们,而是 (可能几年后?Java 的历史说得更好) 作为约定:一对一致的 getter/setter 是bean中的property,属性的概念在库中,不在核心中。

                  这会在少数库、框架中产生问题。单个 getter 是否是只读属性?就是那个问题。即在 JPA 实体中,如果您想实现以“get”开头的经典方法(算法),例如 getCurrentTine(),是 @Transient 禁用具有价值的属性的解释的最佳标记。

                  换句话说,我非常喜欢 10 年后设计的 C# 中的属性概念,并且更好。顺便说一句,C# 属性也有 getter/setter,但有时/部分隐藏,在低级调试时可见。没有“为什么是吸气剂”等问题......

                  在 Java 世界中,阅读 Groovy 的属性概念很有趣(隐藏的 getter/setter 方式与 C# 不同)http://www.groovy-lang.org/objectorientation.html#_fields_and_properties

                  编辑:在现实生活中,每个 java 对象都有getClass() 方法,java.beans.BeanInfo 包中的工具将此报告为属性"class",但这不是真的。它不是完全意义上的财产(只读财产)。我想像 C# 之类的属性(他的内部隐藏名称 get_Something1)与“功能性”GetSomething2() 没有冲突

                  【讨论】:

                    猜你喜欢
                    • 2014-12-20
                    • 2010-11-30
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2023-03-09
                    • 2014-04-18
                    • 1970-01-01
                    • 2011-05-25
                    相关资源
                    最近更新 更多