代码之家  ›  专栏  ›  技术社区  ›  GuruKulki

多次调用getter还是一次调用并分配给变量?

  •  13
  • GuruKulki  · 技术社区  · 15 年前

    假设我的课是:

    public class Age {
    
        private int age;
    
        public int getAge() {
           return this.age;
        }
    
    }
    

    在我的主班里,我打电话给 getAge() 方法多次。

    所以我想知道,多次调用或一次调用并将其赋给某个变量并使用该变量是否明智。

    哪一个最好,为什么?

    12 回复  |  直到 7 年前
        1
  •  10
  •   unholysampler    15 年前

    这很可能是一种情况,在您知道需要优化之前,您正在进行优化。该值只是一个整数,因此如果将该值存储在多个位置,则不会占用大量内存。同时,它是一个非常简单的方法调用,执行起来不会花费太多时间。用你觉得最易读的方式写。然后,在您有了代码的可靠版本之后,您可以使用一个分析工具来查看是否存在显著的差异。

        2
  •  7
  •   Reed Copsey    15 年前

    不要试图对其进行微观优化,除非在分析时发现这确实是一个瓶颈。我将使用getage()访问器方法,因为它很可能是最容易维护和最明显的解决方案。

    也就是说,这两种方法的性能可能完全相同。在运行时,JIT很可能会完全优化getage()调用,因此在这两种情况下,它都是一个单一的基元访问。

        3
  •  3
  •   Cesar    15 年前

    调用 getAge() 方法很多次,但我建议你考虑 The Sad Tragedy of Micro-Optimization Theater .

        4
  •  3
  •   Uri    15 年前

    作为API编写者,您必须向调用者指出这一点。

    通常,如果您只是返回一个属性,那么可以将调用标记为最终调用(如果您没有提供实际的接口)。这将降低调用的成本,因为编译器更可能内联函数。

    如果计算该属性的成本很高(例如,字符串查找),请将其记录在该方法的javadocs中,并向调用者指示他们可能希望获取该值一次并将其缓存。

        5
  •  2
  •   Puppy    15 年前

    别麻烦了。这样的微优化绝对不值得。等到你完成你的代码,然后它运行得太慢,然后拿出一个分析器,研究分析器告诉你的是问题的根源。

    过早的优化是万恶之源。

        6
  •  1
  •   Jordão    15 年前

    根据应用程序的设计方式,这两个选项实际上可能会给出不同的结果!如果正在使用的年龄实例是共享的和可变的,则应用程序中的不同位置可能会在调用 getAge() . 在这种情况下,决定哪一个是代码的最佳选择是正确的,这取决于您自己决定。正如古老的格言所说:“先改正,然后再加快”。而且,正如其他人已经提到的,在本例中,您可能不需要担心“使它快速”这一部分。

    一个相关的例子是当您在迭代一个集合时更改它。您必须迭代快照才能获得 ConcurrentModificationException .

        7
  •  1
  •   Felipe Cypriano    15 年前

    我将尝试用代码示例来说明另一个答案已经说过了什么。

    在本例中,您提出了对getage()的调用非常简单,调用它的成本几乎为零。在这种情况下,不要麻烦它。

    但是,如果您的getage是一种花哨的东西,可以进行大量计算或访问IO资源,例如:

    public int getAge() {
       return slowService.calculateAgeByBirthDate(birthDate); // it takes 2 seconds to execute for every call
    }
    

    当然,最好是缓存并使用结果。因为如果你调用它30次,你的代码需要1分钟才能完成。

        8
  •  0
  •   Randy    15 年前

    我认为你在运行时不会看到任何区别——假设你不创建多个年龄段的类。

        9
  •  0
  •   aioobe    15 年前

    对于这样一个简单的例子,我会选择一个看起来最适合代码的例子。

    在一些情况下,建议调用一次并读取保存的返回值,例如

    for (int i = 0; i < list.size(); i++)
        doSomethingThatDoesNotAffectSizeOfList();
    

    因为编译器可能无法确定循环体是否影响列表的大小。一个正确实现的列表应该总是能够轻松地告诉它的大小,但是在其他示例中(或者在处理实现不好的集合时),它可能会更糟。

    通常,如果一个方法的计算量很大,则可以使用 memoization ,这基本上意味着您缓存已经计算的输入/输出值。

    一个记忆函数“记忆”对应于一组特定输入的结果。具有记住输入的后续调用返回记住的结果,而不是重新计算结果,从而消除了具有给定参数的调用的主要成本,而不是使用这些参数对函数进行的第一次调用。

    该技术将“节省效率的返回值”推送到方法本身,从而简化了对BLA BLA BLA BLA的维护。

        10
  •  0
  •   Thorbjørn Ravn Andersen    15 年前

    棘手的部分是理解现代JVM在基于运行时可用的知识编译字节代码时会进行积极的优化。

    例如,如果一个给定的方法没有在子类中被重写,它可以被视为一个完全相同的最终方法,允许JVM在调用方法中内联其代码的副本,而不是显式地执行方法调用。(如果条件发生变化,那么这些类将被简单地视为新的,因此稍后将根据新的条件重新编译)。

    这意味着bean属性的get/set(其中值只是简单地存储和检索,而不是计算)非常便宜,您应该每次都进行调用,并期望JVM检测到可能的优化并应用它们。

        11
  •  0
  •   Phani    15 年前

    除非在getage()方法中执行许多操作,否则性能不会有太大的变化。

        12
  •  0
  •   cthulhu    15 年前

    在这种情况下,我建议不要考虑性能、可用性和代码重用。您当前的实现是最简单的getter,它返回一个整数。

    但是,如果你将某人的出生日期存储在一行的某个地方,并且想要动态地生成年龄呢?如果您只是直接调用属性,那么就必须重构代码。但是,更改getage()的内部结构,您可以将计算放在其中,然后就完成了。

    我真的希望编程语言引入一个“超级私有”属性/字段修饰符,它基本上说“您只能通过它的访问器访问这个属性”。

    推荐文章