8

做有什么区别吗

Field field = something.getSomethingElse().getField();
if (field == 0) {
//do something    
}
somelist.add(field);

相对

if (something.getSomethingElse().getField() == 0) {
//do something    
}
somelist.add(something.getSomethingElse().getField());

通过 getter 引用该字段会导致性能损失还是与引用分配的变量相同?我知道该变量只是对内存空间的引用,因此 getter 应该只是获取该内存空间的另一种方式。

请注意,这是一个学术问题(只是好奇的学校),而不是一个实际问题。

4

9 回答 9

12

这是一个可以忽略不计的损害。不要太在意它,否则你会成为过早优化的牺牲品。如果您的应用程序很慢,这不是原因。

于 2009-07-28T18:29:05.587 回答
8

假设getSomethingElse()定义为

public SomethingElse getSomethingElse() {
    return this.somethingElse;
}

性能差异将是最小的(如果它会被内联,则为零)。然而,在现实生活中,你不能总是确定是这样 - 可能在幕后发生了一些处理(不一定在对象本身中,而是通过 AOP 代理)。因此,将结果保存在变量中以供重复访问可能是一个好主意。

于 2009-07-28T18:30:59.497 回答
6

不同之处在于,通过 getter 访问变量会导致方法调用。可以想象,JVM 在某些情况下能够优化方法调用,但它一个方法调用。

也就是说,如果您的代码中最大的瓶颈或性能问题是访问器方法的开销,我会说您不必担心太多。

于 2009-07-28T18:30:04.507 回答
4

存在性能损失(可能很小,可以忽略不计)但是,JVM 可能会内联这个以及所有提高性能的调用。

如果你以第二种方式离开它会更好。

于 2009-07-28T18:29:21.247 回答
3

如果你有一个好的 JVM,比如 Sun 的 HotSpot,就不会。它将内联并编译(本机代码)getter。

使用 getter 通常是一种非常好的做法,作为一种防御措施,以及一般的信息隐藏。

于 2009-07-28T18:29:47.707 回答
2

如果使用 Java 编写 Android 应用程序,需要注意的一点是:http: //developer.android.com/training/articles/perf-tips.html#GettersSetters

在 C++ 等本地语言中,通常使用 getter (i = getCount()) 而不是直接访问字段 (i = mCount)。这对于 C++ 来说是一个很好的习惯,并且在 C# 和 Java 等其他面向对象的语言中经常练习,因为编译器通常可以内联访问,如果您需要限制或调试字段访问,您可以随时添加代码。

但是,这在 Android 上是个坏主意。虚拟方法调用很昂贵,比实例字段查找要贵得多。遵循常见的面向对象编程实践并在公共接口中使用 getter 和 setter 是合理的,但在类中,您应该始终直接访问字段。

如果没有 JIT,直接字段访问比调用普通 getter 快大约 3 倍。使用 JIT(直接字段访问与访问本地一样便宜),直接字段访问比调用普通 getter 快约 7 倍。

请注意,如果您使用 ProGuard,则可以两全其美,因为 ProGuard 可以为您内联访问器。

于 2014-10-06T10:32:56.757 回答
0

如果该方法是一个简单的 getter,不涉及任何处理,那不是问题。如果它涉及大量计算,那么一个属性无论如何都不会做你想做的事。

唯一一次我担心任何差异是在具有大量迭代(数千次)的紧密循环中。即使这样,如果您使用方面来编织额外的处理(例如日志记录),这可能只是一个问题,这可能涉及创建数千个额外的对象(例如 JoinPoints 和参数自动装箱)和由此产生的 GC 问题。

于 2009-07-28T18:37:53.993 回答
0

我不会担心性能差异。您最好不要考虑它,而是花时间在现实场景中分析您的代码。您很可能会发现程序的慢速部分并不像您认为的那样。

于 2009-07-29T10:27:01.677 回答
0

这篇文章讨论的是 CLI VM 而不是 JVM,但每个都能够做类似的事情,所以我相信它是相关的。

我正在以一种特殊的方式为我的 JIT 处理这个特殊问题。请注意,这里的描述是概念性的,出于性能原因,代码以稍微不同的方式实现它。当我加载一个程序集时,如果它只是返回一个成员字段,我会在方法描述符中做一个注释。稍后当我 JIT 其他方法时,我将call字节码中对这些方法的所有指令替换为一条ldfld指令,然后再将其传递给本机代码生成器。这样,我可以:

  1. 在 JIT 中节省时间(比 JITldfld花费更少的处理器时间call)。
  2. 甚至在基线编译器中的内联属性。
  3. 总的来说,当调试器分离时,使用公共属性/私有字段模式不会导致任何类型的性能损失。(当附加了调试器时,我无法内联访问器。)

我毫不怀疑,VM 技术中的大牌已经在他们的产品中实现了与此类似(并且可能更好)的东西。

于 2009-08-03T06:24:52.690 回答