java在局部变量中缓存属性吗?
考虑类^ {CD1>}。
public class Foo {
private double size;
public double getSize() {
return this.size; // Always O(1)
}
}
Foo
有一个名为size的属性,该属性经常被给定的方法访问,但从未修改过。每当在任何方法中多次访问某个属性时,我总是将其缓存在变量中,因为“有人告诉我是这样的”,我没有仔细考虑它。i、 e
public void test(Foo foo) {
double size = foo.getSize(); // Cache it or not?
// size will be referenced in several places later on.
}
这是值得的,还是过火了
如果我不缓存它,现代编译器是否足够聪明,可以自己缓存它
# 1 楼答案
依我看,如果你真的担心性能的话,这有点过分了或太过广泛了,但是有几种方法可以确保变量被你的虚拟机“缓存”
首先,您可以创建结果的最终静态变量(根据您的示例1或0),因此整个类只存储一个副本,然后您的局部变量只是一个布尔值(仅使用1位),但仍然保持结果值double(此外,如果仅为0或1,您也可以使用int)
或者,如果您能够在初始化类时设置大小,您可以使用此选项,您可以通过构造函数和static设置最终变量,但由于这是一个局部变量,您可以使用构造函数:
这可以通过
foo.getSize()
访问# 2 楼答案
当决定是否存储调用“GET()”方法返回的值时,我考虑的几个因素(
)get()方法的性能-除非API指定,或者除非调用代码与被调用方法紧密耦合,否则get()方法的性能没有保证。现在进行测试时,代码可能还可以,但是如果get()方法在将来性能发生变化,或者如果测试没有反映实际情况,代码可能会变得更糟。(例如,在一个容器中仅使用1000个对象进行测试,而现实世界中的容器可能有1000万个对象)用于for循环,每次迭代之前都会调用get()方法
可读性-可以为变量指定一个特定的描述性名称,以一种对get()方法的内联调用可能不清楚的方式澄清其用法和/或含义。不要低估这对那些审查和维护代码的人的价值
线程安全性-如果调用方法执行操作时另一个线程修改对象,get()方法返回的值是否可能更改?这样的更改应该反映在调用方法的行为中吗
关于编译器是否会自己缓存它的问题,我想推测一下,在大多数情况下,答案必须是“否”。编译器安全地执行此操作的唯一方法是确定get()方法在每次调用时返回相同的值。只有当get()方法本身被标记为final,并且它所做的只是返回一个常量(即一个对象或原语也被标记为final)时,才能保证这一点。我不确定,但我认为这可能不是编译器所关心的场景。JIT编译器有更多的信息,因此可以具有更大的灵活性,但不能保证某些方法会得到JIT
总之,不要担心编译器会做什么。缓存get()方法的返回值可能在大多数情况下都是正确的,很少(即几乎从不)是错误的。喜欢编写可读和正确的代码,而不是快速(est)和华而不实的代码
# 3 楼答案
最大的因素是性能。如果这是一个不需要大量CPU周期的简单操作,我会说不要缓存它。但如果您经常需要对不变的数据执行昂贵的操作,那么一定要缓存它。例如,在我的应用程序中,当前登录的用户在每个页面上都以JSON格式序列化,序列化操作非常昂贵,因此为了提高性能,我现在在用户登录时序列化一次用户,然后使用序列化版本将JSON放在页面上。以下是在性能方面取得显著改进的前后步骤:
//以前
//之后
用户对象没有setter方法,除非用户注销然后重新登录,否则数据不会更改,所以在这种情况下,我认为缓存值是安全的
# 4 楼答案
如果每次都计算size的值,比如通过数组循环,而不是O(1),那么缓存该值将在性能方面有明显的好处。然而,由于Foo的size在任何时候都不会改变,并且是O(1),因此缓存该值主要有助于提高可读性。我建议继续缓存该值,因为在现代计算系统中,可读性往往比性能更令人担忧
# 5 楼答案
我不知道是否有一个“正确”的答案,但我会保留一份本地副本
在您的示例中,我可以看到
getSize()
是微不足道的,但在实际代码中,我并不总是知道它是否微不足道;即使它在今天是琐碎的,我也不知道有人不会来改变getSize()
方法,使它在将来某个时候变得不琐碎# 6 楼答案
在我的代码中,如果getSize()方法非常耗时,或者(更常见的情况是)结果用于或多或少复杂的表达式中,我会缓存它
用于计算偏移量的大小,例如
(对我来说)读起来比读起来容易