https://segmentfault.com/q/1010000040896700
问题
在对象的方法中使用对象的成员变量时,为什么喜欢先把它赋值给这个方法的局部变量?为了不可变性吗?
先上代码:
public class SomeObject{
private Subscription subscription;
public void foo(long n){
Subscription s = this.subscription;
s.request(n);
}
}
反正自己平时写代码时,在foo(n)中就直接掉用this.subscription.request(n)了。但其实仔细想想,好像很多比较规范的源码中都会先把成员变量赋值给一个方法的局部变量,再操作这个局部变量。
我个人的第一感觉是:是不是防止在代码中出现类似下面的代码,进而造成改变了成员变量的实时。即:从类的不变性角度触发才像上面这样写:
public void foo(long n){
//写代码、或修改代码时,在这个方法中需要换一个subscription对象
if(
this.subscription.request(n)
.notSatisfySomeCondition()
){
this.subscription = new AnotherSubscriptionImpl();
this.subscription.request(n);
}
}
个人感觉自己这样理解没问题,有谁能给个准话吗?
类似的代码还有很多,我挑几个立即就能想到的:
//reactor-core的BaseSubscriber.java
@Override
public final void request(long n) {
if (Operators.validate(n)) {
Subscription s = this.subscription;
if (s != null) {
s.request(n);
}
}
}
//HashMap的随便一个方法,如putVal(...)
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
//这里的tab = this.table 源码是tab=table,这里为了突出效果而加了this.
if ((tab = this.table) == null || (n = tab.length) == 0)
//...process with tab but not table
}
补充:这里不是要讨论不可变类的实现,因为它的内容比较多。
回答
你可以看下我上图的例子,对比一下左侧代码23行和25,以及右侧生成的字节码。你会发现获取b和c只需要调用iload,从本地方法栈取值,但是获取a的时候,aload->获取this,getfield->获取a的值,需要两步操作。
如果代码里都是使用成员变量,那么底层字节码每次都要先获取this,再getfield.而赋值给局部变量后就直接load局部变量就好了
.
把成员变量赋值给局部变量是为了抠性能,对于底层还是有必要的,
对于业务层就比较无所谓了