Java中合理使用局部变量替代成员变量静态变量
Posted Danny_姜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中合理使用局部变量替代成员变量静态变量相关的知识,希望对你有一定的参考价值。
故事起因
一个Java类中可以存在多种形式的变量,可以是最一般的成员变量、或静态变量、或临时变量。如下图:
public class VariableDemo
static int staticValue = 0; // 静态变量
int fieldValue; // 全局变量
public int getMultiValue()
int localValue = 10; // 局部变量
return localValue * 2;
图中的staticValue、fieldValue和方法内部的localValue分别为静态变量、成员变量和局部变量。
但是在我阅读android或者是JDK源码时,经常看到以下形式的代码:
public class Hashtable
private transient HashtableEntry<?,?>[] table;
private void addEntry(int hash, K key, V value, int index)
HashtableEntry<?,?> tab[] = table;
...
// Creates the new entry.
HashtableEntry<K,V> e = (HashtableEntry<K,V>) tab[index];
tab[index] = new HashtableEntry<>(hash, key, value, e);
count++;
上图中,在HashTable源码的 addEntry 方法内部创建了一个临时的局部变量tab,用来替代成员变量table,并且后续的操作都由tab对象来执行。
那么这么做的意义是什么呢?
实践检验
这3种变量的存取效率是有区别的,合理使用这3种变量能够帮助我们实现更高性能的代码。可以用一个简单的例子来展示这3种变量各自的存取效率,如下代码:
package com.subject.variable;
/**
* 使用临时变量提高Java代码性能
*/
public class VariableDemo
private long instVar;// 成员变量
private static long staticVar; // 静态变量
// 存取类方法中的临时变量
void tempAccess(long val)
int j = 0;// 临时变量
long startTime = System.currentTimeMillis();
for (long i = 0; i < val; i++)
j += 1;
long endTime = System.currentTimeMillis();
System.out.println("temp var: " + (endTime - startTime) + " milli seconds");
// 存取类的成员变量
void instanceAccess(long val)
long startTime = System.currentTimeMillis();
for (long i = 0; i < val; i++)
instVar += 1;
long endTime = System.currentTimeMillis();
System.out.println("instance var: " + (endTime - startTime) + " milli seconds");
// 存取类的 static 变量
void staticAccess(long val)
long startTime = System.currentTimeMillis();
for (long i = 0; i < val; i++)
staticVar += 1;
long endTime = System.currentTimeMillis();
System.out.println("static var: " + (endTime - startTime) + " milli seconds");
public static void main(String[] args)
VariableDemo test = new VariableDemo();
long count = 10 * 1000 * 1000 * 1000L;
test.tempAccess(count);
test.instanceAccess(count);
test.staticAccess(count);
解释说明:
这段代码中的每个方法都执行相同的循环,并反复相同的次数。唯一的不同是每个循环使一个不同类型的变量递增:
tempAccess 使一个方法的局部变量递增
instanceAccess 使类的一个成员变量递增
staticAccess 使类的一个静态变量递增
计算结果如下:
temp var: 2987 milli seconds
instance var: 4039 milli seconds
static var: 3996 milli seconds
从结果中可以发现,instanceAccess 和 staticAccess 的执行时间基本相同。但是,tempAccess 要快两到三倍。
原理分析
存取堆栈变量如此快是因为JVM 存取局部变量的存取效率比它成员变量 或静态变量更高。
JVM 是一种基于堆栈的虚拟机,每一个方法对应一个栈帧,每个方法在线程中执行时,都会通过栈帧的形式进行运算。如下图:
所有局部变量都存储在一个栈帧中的局部变量表中,通过局部变量表与操作数栈的协同合作,局部变量可以被高效地存取。
相比之下,成员变量和静态变量的存取成本就相对较高。因为 JVM 必须使用代价更高的操作码,并从常数存储池中存取它们。(常数存储池保存一个类型所使用的所有类型、字段和方法的符号引用)。通常,在第一次从常数存储池中访问成员变量或静态变量以后,JVM 将动态更改字节码以使用效率更高的操作码。尽管有这种优化,堆栈变量的存取仍然更快。
注意:这也是为什么JVM会自动优化成员变量转化为局部变量,详细内容可以参考链接:不要让你的 Java 对象"逃逸"了!
代码优化
具体优化措施可以参考文章开头介绍的Android或Java源码中的做法,使用局部变量替换成员变量或者静态变量,以便通过基于栈操作使代码运行更加高效。
package com.subject.variable;
/**
* 使用临时变量提高Java代码性能
*/
public class VariableDemo2
private long instVar;// 成员变量
private static long staticVar; // 静态变量
// 存取类方法中的临时变量
void tempAccess(long val)
int j = 0;// 临时变量
long startTime = System.currentTimeMillis();
for (long i = 0; i < val; i++)
j += 1;
long endTime = System.currentTimeMillis();
System.out.println("temp var: " + (endTime - startTime) + " milli seconds");
// 存取类的成员变量
void instanceAccess(long val)
long startTime = System.currentTimeMillis();
long tmp=instVar;
for (long i = 0; i < val; i++)
tmp += 1;
instVar=tmp;
long endTime = System.currentTimeMillis();
System.out.println("instance var: " + (endTime - startTime) + " milli seconds");
// 存取类的 static 变量
void staticAccess(long val)
long startTime = System.currentTimeMillis();
long tmp=staticVar;
for (long i = 0; i < val; i++)
tmp += 1;
staticVar=tmp;
long endTime = System.currentTimeMillis();
System.out.println("static var: " + (endTime - startTime) + " milli seconds");
public static void main(String[] args)
VariableDemo2 test = new VariableDemo2();
long count=10*1000*1000*1000L;
test.tempAccess(count);
test.instanceAccess(count);
test.staticAccess(count);
计算结果:
temp var: 2973 milli seconds
instance var: 3074 milli seconds
static var: 3018 milli seconds
如果你喜欢本文
长按二维码关注
以上是关于Java中合理使用局部变量替代成员变量静态变量的主要内容,如果未能解决你的问题,请参考以下文章