バイトコード分析を使用するか、 を使用して 2 つのアプローチの時間を計りますSystem.nanoTime
。2番目の方が速いと思います。これを結論付けるために私がしたことは次のとおりです。
以下に示すように、3つのクラスを作成しました。
public static class A {
public B b = new B();
}
public static class B {
public E e = new E();
}
public static class E {
public String name = "s";
public int age = 1;
}
次に、2 つの単純なメソッドを作成し、javap -c CLASS_NAME
.
public static void Test1() {
A a = new A();
String str = a.b.e.name;
int age = a.b.e.age;
}
上記のメソッドのバイトコードは次のとおりです。
public static void Test1();
Code:
// new A();
0: new #15
3: dup
4: invokespecial #17
7: astore_0
8: aload_0
// a.b (it accesses the field and put it on operand stack)
9: getfield #18
// b.e
12: getfield #22
// b.name
15: getfield #28
// pop 'name' from stack
18: astore_1
19: aload_0
// cyle continues
20: getfield #18
23: getfield #22
26: getfield #34
29: istore_2
30: return
バイト コード レベルではっきりと確認できます。フィールドにアクセスしようとするたびに、そのフィールドの値がスタックに置かれ、このサイクルが続きます。したがって、スタックがすべてを保持するのに十分なスペースを持っている場合、命令になりa.a1.a2....an
ます。そして、フィールドとフィールドの両方にアクセスするために再度呼び出されるこの同じサイクルのコンパイラによる最適化はありませんでした。n
n
name
age
次に、2 番目の方法を示します。
public static void Test2() {
A a = new A();
E e = a.b.e;
String str = e.name;
int age = e.age;
}
上記のメソッドのバイト コードは次のとおりです。
public static void Test2();
Code:
// new A();
0: new #15
3: dup
4: invokespecial #17
7: astore_0
8: aload_0
// store a.b.e on operand stack once
9: getfield #18
12: getfield #22
15: astore_1
16: aload_1
// get 'name' field
17: getfield #28
20: astore_2
21: aload_1
// get 'age' field
22: getfield #34
25: istore_3
26: return
上記は の実行を妨げるため、前のコードよりも 4 命令短くなりgetfield
ます。したがって、これは以前のものよりも高速である必要があると思います。