3 super(…)の前の文

コンストラクタでは、明示的なコンストラクタ呼出しの前に、作成されるインスタンスを参照しない文を追加できます。

ノート:

これはプレビュー機能です。プレビュー機能は、設計、仕様および実装が完了したが、永続的でない機能です。プレビュー機能は、将来のJava SEリリースで、異なる形式で存在することもあれば、まったく存在しないこともあります。プレビュー機能が含まれているコードをコンパイルして実行するには、追加のコマンド行オプションを指定する必要があります。『Preview Language and VM Features』を参照してください。

super(...)の前の文の背景情報は、JEP 447を参照してください。

この機能を使用すると、自明でない計算を実行することでスーパークラス・コンストラクタの引数を準備したり、スーパークラス・コンストラクタに渡す引数を検証できます。次の例では、引数valueをスーパークラス・コンストラクタに渡す前に、正かどうかを検証します。

public class PositiveBigInteger extends BigInteger {

    public PositiveBigInteger(long value) {
        if (value <= 0)
            throw new IllegalArgumentException("non-positive value");
        super(Long.toString(value));
    }
}

コンストラクタの本体のプロローグは、super(...)呼出しの前に出現する文で構成されます。コンストラクタの本体のエピローグは、super(...)呼出しに続く文で構成されます。

コンストラクタの構築前コンテキスト

コンストラクタの構築前コンテキストは、super(...)などの明示的なコンストラクタ呼出しの引数と、その前の文で構成されます。

前述の例では、PositiveBigIntegerの構築前コンテキストは、引数valueと、valueが正かどうかをチェックするif文で構成されます。

構築前コンテキスト内のコードは、構築中のインスタンスにはアクセスできません。これは、構築前コンテキストでは次のものを使用できないことを意味します。

  • 修飾されていないthis: thisキーワードを使用して、構築中のインスタンスにアクセスする必要はありません。たとえば:

    class A {
        int i;
        A() {
            // Error: Cannot reference this before supertype constructor has been
            //        called
            this.i++;
    
            // Error: cannot reference i before supertype constructor has been
            //        called        
            i++;     
            
            // Error: cannot reference this before supertype constructor has been
            //        called
            this.hashCode();
            
            // Error: cannot reference hashCode() before supertype constructor has
            //        been called
            hashCode();
            
            // Error: cannot reference this before supertype constructor has been
            //        called        
            System.out.print(this);
            super();
        }
    }
  • superで修飾されたフィールド・アクセス、メソッド呼出しまたはメソッド参照: 同様に、superキーワードを使用して、構築中のインスタンスのスーパークラスにアクセスする必要はありません。

    class D {
        int j;
    }
    
    class E extends D {
        E() {
            // Error: cannot reference super before supertype constructor has been
                      called
            super.j++;  
            
            // Error: cannot reference j before supertype constructor has been
            //        called
            j++;
            super();
        }
    }

ネストされたクラス

ネストされたクラスは、その包含クラスのメンバーであり、その包含クラスの構築前コンテキストからネストされたクラスにアクセスできないことを意味します。たとえば:

class B {
    
    class C { }
    
    B() {
        // Error: cannot reference this before supertype constructor has been
        //        called
        new C();
        super();
    }
}

ただし、ネストされたクラスの包含クラスは、そのメンバーの1つではありません。つまり、その包含クラスには、その構築前コンテキストからアクセスできます。次の例では、ネストされたクラスGの構築前コンテキストでFのメンバー変数fとメソッドhello()の両方にアクセスできます。

class F {
    
    int f;
    
    void hello() {
        System.out.println("Hello!");
    }
    
    class G {
        G() {
            F.this.f++;
            hello();
            super();
        }
    }
}

レコード

レコード・コンストラクタは、super(...)を呼び出すことはできません。ただし、this(...)を呼び出して、非標準コンストラクタに標準コンストラクタを含める必要があります。文は、this(...)の前に記述できます。

標準コンストラクタは、レコードのコンポーネント・リストと同じシグネチャを持つコンストラクタであることに注意してください。レコード・クラスのすべてのコンポーネント・フィールドが初期化されます。代替または非標準のレコード・コンストラクタには、レコードの型パラメータと一致しない引数リストがあります。

次の例では、レコードRectanglePairに非標準コンストラクタRectanglePair(Pair<Float> corner)が含まれています。これは非標準コンストラクタであるため、this(...)を使用して標準コンストラクタを呼び出す必要があります。this(...)の前に、Pair<Float> パラメータから両方の値を取得し、これらの値が負でないことを検証するいくつかの文が含まれています。

record Pair<T extends Number>(T x, T y) { }

record RectanglePair(float length, float width) {
    public RectanglePair(Pair<Float> corner) {
        float x = corner.x().floatValue();
        float y = corner.y().floatValue();
        if (x < 0 || y < 0) {
            throw new IllegalArgumentException("non-positive value");
        }
        this(corner.x().floatValue(), corner.y().floatValue());
    }
}

詳細は、「レコード・クラス」「代替レコード・コンストラクタ」を参照してください。