getter对Java的性能有害吗?

Nic*_*ole 0 java performance encapsulation

鉴于以下两个代码选项,第二个代码选项是否有任何性能优势(超过大规模或长时间)?

选项1

private Map<Long, Animal> animals = ...;
public Map<Long, Animal> getAnimals() {
    return animals;
}

public void useAnimals() {
    for (int i=0; i < SOME_LARGE_NUMBER; i++) {
        Animal animal = getAnimals().get(id);
    }
    // Many many calls to getAnimals() are made...
}
Run Code Online (Sandbox Code Playgroud)

选项2 - 没有吸气剂

private Map<Long, Animal> animals = ...;

public void useAnimals() {
    for (int i=0; i < SOME_NUMBER; i++) {
        Animal animal = animals.get(id);
    }
    // No method calls made
}
Run Code Online (Sandbox Code Playgroud)

如果它对性能有害,为什么,以及我该如何确定它是否值得减轻?

并且,将存储结果getAnimals()作为本地提供一个好处...

  • 如果SOME_NUMBER是数百或数千?
  • 如果SOME_NUMBER只是10的数量级?

注意:我之前说过"封装".我将其更改为"getter",因为其目的实际上不是该字段无法修改,而是无法重新分配.封装只是为了从子类中删除赋值的责任.

Tom*_*icz 7

很可能JVM会getAnimals()在紧密循环中内联调用,有效地回退到选项1.所以不要打扰,这实际上是微观(纳米?)优化.

另一件事是从字段访问迁移到本地变量.这听起来不错,因为this每次总是在堆栈上有一个引用(两次内存访问与一次)时,不是遍历引用.但是我相信(如果我错了,请纠正我),因为它animals是私有的,而且非volatileJVM将在运行时为您执行此优化.

  • @Renesis,你没有抓住重点,这对 JIT 来说都不重要,它在后台默默地完成这一切,比你以前能做得更好。您甚至可以通过尝试再次猜测 JIT 来阻止它进行其他优化。编写合理且可维护的代码,让编译器和 JIT 处理这个**亚微**性能问题。如果您如此担心这些微小的实现细节可能会因版本而异,请使用 C 代码。 (2认同)

JB *_*zet 5

第二个片段比第一个片段封装.第一个允许访问任何人的内部映射,而第二个将它封装在类中.

两者都将带来可比的表现.

编辑:既然你改变了问题,我也会改变答案.

如果你通过一个getter,并且getter不是final,这意味着子类可能会返回另一个映射,而不是你在类中保存的映射.选择是否希望您的方法在子类的地图上或在类的地图上操作.两者都可以接受,具体取决于具体情况.

无论如何,假设您的子类总是制作地图的防御性副本,如果不将getter的结果缓存在局部变量中,则最终会有很多副本useAnimals.可能需要始终处理子类映射的最新值,但我怀疑是这种情况.

如果没有子类,或者子类没有覆盖该方法,或者通过始终返回相同的映射来覆盖它,则两者都将导致可比较的性能,您不应该关心它.