2011-12-21 4 views
8

はのは、私がFractionクラスがあるとしましょう:次のコードは、Javaバイトコードの新しい+ dup命令に変換されるのはなぜですか?

class Fraction { 
    ... 

    /** Invert current fraction */ 
    public Fraction inverse() { 
     return new Fraction(den,num); 
    } 

    ... 
} 

そして、これは、上記の方法のバイトコードがあることが判明何である:

0 new #1 <xyzTestes/system/fraction/Fraction> 
3 dup 
4 aload_0 
5 getfield #16 <xyzTestes/system/fraction/Fraction.den> 
8 aload_0 
9 getfield #14 <xyzTestes/system/fraction/Fraction.num> 
12 invokespecial #27 <xyzTestes/system/fraction/Fraction.<init>> 
15 areturn 

私は3位の理由命令を理解しようとしていますそこに最初に置かれた。

new #1 <xyzTestes/system/fraction/Fraction> 
aload_0 
getfield #16 <xyzTestes/system/fraction/Fraction.den> 
aload_0 
getfield #14 <xyzTestes/system/fraction/Fraction.num> 
invokespecial #27 <xyzTestes/system/fraction/Fraction.<init>> 
areturn 

なぜそうでないのですか?

答えて

10

コンストラクタのバイトコードが開始されるとき、Fractionオブジェクトはありません。 new命令は、ヒープからFractionオブジェクト(初期化されていない)を割り当て、そのオブジェクトへの参照をスタックに残します。 dup命令は、1つの参照が<init>を呼び出すために使用され、最後の参照がareturnの最後に使用されるようになっています。

+0

invokespecialは、Fractionへの参照をスタックに入れません。 –

+5

@devoured elysium '()Vは 'Fraction'ではなく' void'を返します。 –

+0

メー、そうです。 –

8

バイトコードが正しくありません。のは、それをステップ実行してみましょう:

new #1 <xyzTestes/system/fraction/Fraction> 

スタックFractionインスタンス(メモリに初期化されていない、唯一のポインタ)

aload_0 

スタックFraction(まだ初期化されていない)、this

getfield #16 <xyzTestes/system/fraction/Fraction.den> 

スタックFraction(まだ初期化されていない)、this.den

aload_0 
getfield #14 <xyzTestes/system/fraction/Fraction.num> 

スタックFraction(まだ初期化されていない)、this.denthis.num

invokespecial #27 <xyzTestes/system/fraction/Fraction.<init>> 

スタック

これは非常に重要です。すべてのinvokeメソッドは、スタックにthis +すべての引数を含める必要があります。 thisと引数は両方ともスタックから取得されます。呼び出しの後に戻り値(もしあれば)だけがスタックに置かれます。 <init>にはvoidの戻り値があります。

これは、あなたが呼び出します:空のスタックに

areturn 

、JVMを吹き出します。

関連する問題