【问题标题】:Java language convention; getters/settersJava 语言约定;获取器/设置器
【发布时间】:2010-05-19 11:39:00
【问题描述】:
Public class Example {

    private int number;

    public Example(int number){
        this.number = number;
    }

    public int getNumber(){
        return number;
    }

    public void setNumber(int number){
        this.number = number;
    }

    public static void main(String[] args){
        Example e = new Example(5);

在访问自己的类中的变量时首选什么; “e.number”还是“e.getNumber()”?

编辑
我认为最重要的问题是:编译器是否知道您调用的方法是 getter 或 setter。那么,e.setNumber(5); 会和e.number = 5; 一样快吗

【问题讨论】:

  • 为什么这是一个重要的问题?标题清楚地表明问题是关于约定的。

标签: java performance program-flow


【解决方案1】:

e.getNumber() 是常用的方法。所以getset + VariableName

你也可以看看HERE

【讨论】:

  • 这也是 Sun 建议的 Java 编码约定。
  • @Chris,愿意提供一个网址吗?
  • 你能指出确切的段落吗?问题是关于“它自己的类”。
  • 我显然没有关注“它自己的类”。 :(
【解决方案2】:

我会说这取决于情况。如果该字段很简单,例如 int 并且将来不太可能更改,我将使用 number 而不是 getNumber() 访问它。

如果该字段代表的内容更多,可能在某些情况下计算在未来的情况下或可能在子类中覆盖getNumber() 是显而易见的选择。

我的经验法则:如果有任何可以从getNumber() 中受益的微不足道的机会,我使用getNumber(),否则我使用number,为了清晰和简洁。 p>

【讨论】:

    【解决方案3】:
    this.number
    

    在大多数情况下,它们将被优化为相同的代码,但使用 setter/getter 的目的是避免在更改实现时更改 API。但是在课堂上你不使用“API”,但你会看到所有的内部结构和状态。

    另外你可以使用

    numer += 5;
    

    而不是

    setNumber(getNumber() + 5);
    

    编辑:当然,在类之外它应该受到 getter/setter 的保护,因为您可以更改内部表示,并且您可以通过根据新的状态表示重新实现它们来提供向后兼容性。

    编辑 2main 有点特别。我想说main 应该尽可能小——创建一些对象并调用最多一两个方法——因此它不应该分配变量,并且应该作为“外部”部分受到威胁。另一方面,一些在main 中提供了可能需要直接访问状态的测试方法。因此,如果可以的话,您不应该直接访问 main 中的字段。

    main 中的速度而言,无论如何启动JVM 将抵消任何成本都无关紧要。真正的区别在于 JIT 会处理它的内部循环。

    【讨论】:

      【解决方案4】:

      只有当 getter/setter 做一些额外的事情时才会有区别。如果您从一开始就知道会出现这种情况,那么即使在类中也可以使用这些方法。如果不是,我将直接进行字段操作,并在必要时依靠 Eclipse 来帮助我进行重构。

      【讨论】:

        【解决方案5】:

        要回答你的最后一个问题,请看这个例子,

        Java 代码:

        public void test2() {
            setNumber(getNumber() + 1);
        }
        

        字节码:

        public test2()V
           L0
            LINENUMBER 47 L0
            ALOAD 0
            ALOAD 0
            INVOKEVIRTUAL com/test/ByteCodeTester.getNumber()I
            ICONST_1
            IADD
            INVOKEVIRTUAL com/test/ByteCodeTester.setNumber(I)V
           L1
            LINENUMBER 48 L1
            RETURN
           L2
            LOCALVARIABLE this Lcom/test/ByteCodeTester; L0 L2 0
            MAXSTACK = 3
            MAXLOCALS = 1
        

        如您所见,字节码仍会进行 2 次方法调用。所以在这种情况下编译器不会对它有任何不同的处理。

        【讨论】:

        • 字节码显然没有在硬件上执行。字节码很少与 java 代码有很大不同。优化由 jit 完成,在这种情况下,优化是一项微不足道的任务。
        【解决方案6】:

        号码

        除了 number 是基类的私有成员。然后我使用 getter/setter 来说明,它不是扩展类的成员。

        编辑:哦,你在类的主函数中使用它吗?然后就像另一个人说的那样,ofc e.getNumber()。

        【讨论】:

        • 你不能访问子类中的私有成员。
        • 是的,这就是为什么有保护 ;)
        【解决方案7】:

        数字,如果它在同一个类中使用。以及任何子类或外部任何地方的 e.getnumber

        【讨论】:

        • 如果它在同一个类中使用,我会说“数字”,否则就是 e.getNumber。
        • 注意: 方法在 java 中是虚拟的。如果您在同一个类中使用 number 并覆盖 getNumber,您将不会从可能的子类实现中的特化中受益。
        【解决方案8】:

        如果公共访问器出于其他目的而存在,则最好使用此访问器,因为您将确保对变量的一致访问。

        但是,如果您的变量没有公共访问器,则可以直接访问该变量。我倾向于将其限制为私有变量(即代码中没有私有访问器,但如果您需要在基类的实现中访问,则使用受保护的访问器而不是受保护的成员)。

        总结一下:我会一直保持成员私有并通过访问器访问它们,除非唯一需要的访问器是私有的。

        【讨论】:

          【解决方案9】:

          我通常更喜欢使用 setter/getter,即使在内部访问类时也是如此。

          我这样做是因为有时我想修改 getter 使其不仅仅是检索属性(例如延迟加载变量),而且我希望能够灵活地做到这一点而无需担心修改类的其他部分。

          也就是说,也有例外,尽管这些在大多数情况下是个人偏好,而不是一般的最佳实践。我将直接访问成员变量:

          1. 在实现我认为的“低级”功能时(这些完全是主观的,就我而言,我认为#equals()#hashCode()#toString() 和类似的“低级”功能)。我不认为这有很强的技术原因,只是让我“感觉”更好。
          2. 如果其他人指出使用 setter/getter 太不方便(例如,num ++setNumber(getNumber() + 1)。
          3. 如果我的 getter 确实做了一些额外的工作,并且在我的特殊情况下,我想要这种行为。
          4. ...而且我可能还漏掉了其他案例...

          【讨论】:

            【解决方案10】:

            用 this.number=.. 告别多线程,更不用说最终需要实现对 this.number 中的内容的控制。使用 setNumber() Java 得出结论,此方法可能是最终的,并且可以通过优化进行很多操作,因此您感觉不到差异...

            【讨论】:

              【解决方案11】:

              Getter/setter 很好,因为它们通常可以做的不仅仅是作为私有字段的接口。返回/设置的值可能是幕后进行的更复杂计算的一部分。

              然而,危险在于,因为它们是完全成熟的方法调用,它们实际上可以做任何事情 - 启动进程、下载文件、执行昂贵的任务等。从 getter/setter 的上下文来看,这当然是愚蠢的但这是避免做的事情。我还听说过执行 getter/setter 中大部分功能的代码,没有真正的方法!!

              【讨论】:

                【解决方案12】:

                只要安全,JVM 就会优化掉 setter 的方法调用(即几乎在任何情况下,您都想只使用该字段)。因此,对于性能而言,除非您在不进行 JIT 编译的 JVM(例如 Dalvik)上运行,否则这无关紧要。事实上,您可以将方法调用链接到很多层次,当 JVM 实际在硬件上运行时,它会将其优化为仅字段访问。

                因此,您通常不必担心与 getter/setter 相关的性能成本,除非它们真的在做一些额外的事情(在这里,它们不是)。相反,您可以根据其他标准做出决定(您是否希望灵活地更改基础表示?您是否想在以后的类中重新定义它,如果是,重新定义的 setter/getter 是否正确,或者字段访问是否正确? 等)。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2010-09-09
                  • 2014-12-17
                  • 2018-03-29
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多