2

Java 言語では、最終フィールドは初期化時に即時値を取り、変更できなくなります。Java バイトコード (jasmin) では、final フィールドを作成すると、初期化時に割り当てた即時値が無視され、後で他の変数と同じように変更できます。

元。Java コード:

public class App{
    final int CONST = 2;
    App(){
        CONST = 3;
    }
    public static void main(String[] args){
        App app = new App();
    }
}

出力:

App.java:4 error: cannot assign a value to final variable CONST

元。ジャスミンバイトコード:

.class App
.super java/lang/Object

.field private final CONST I = 2 ;!!! the immediate value is ignored, 0 assigned

.method public <init>()V
    .limit stack 3
    .limit locals 1
    aload_0
    invokespecial java/lang/Object/<init>()V

    aload_0
    bipush 3
    putfield App/CONST I ;!!! overwritting final field

    return
.end method

.method public static main([Ljava/lang/String;)V
    .limit stack 1
    .limit locals 1

    new App
    invokespecial App/<init>()V

    return
.end method

出力:

Generated: App.class

エラーはありませんか?新しい CONST 値の出力もテストしましたが、通常の変数と同じように機能します。Java コードのように final フィールドが機能しないのはなぜですか?

4

1 に答える 1

2

Java 言語は、バイトコード レベルでは適用されない多くの制約を適用します。それらの 1 つは、最終フィールドの処理です。

Java バイトコードでは、final フィールドに対する唯一の制約は、static final フィールドを<clinit>メソッドの外側に割り当てることはできず、nonstatic final フィールドを<init>メソッド (つまりコンストラクタ) の外側に割り当てることはできないということです。

final フィールドには、0、1、2、または何回でも割り当てることができます。コンストラクターをチェーンする場合は、1 つのコンストラクターで割り当ててから、別のコンストラクターで上書きできます。

バイトコードの仕組みについて詳しく知るには、JVM 仕様を読む必要があります。

余談ですが、以下は一見類似した構文にもかかわらず、まったく異なるものです。

final int CONST = 2;

.field private final CONST I = 2 ;!!! the immediate value is ignored, 0 assigned

最初の例では、これは (非静的) 初期化子です。すべての初期化子の本体は、事実上、各コンストラクターにコピーペーストされます。CONST = 2したがって、コンストラクターで記述した場合と同じ効果が得られます。

対照的に、Jasmin 構文はConstantValue属性を作成しています。これは通常、静的最終フィールドの初期値を与えるために使用されます。任意のフィールドに指定できますが、非静的フィールドでは無視されるため、値が無視されるのはなぜですか。

于 2016-02-10T16:27:02.060 に答える