S-JIS[2025-09-21] 変更履歴
Javaでthis()・super()の前に文を書けるようにする緩和について。
Java25(プレビュー版ではJava22〜24)で、this()やsuper()の前に文が書けるようになった。
親コンストラクター呼び出し(super())や代替コンストラクター呼び出し(this())の前に文を書くことが出来る。
ただし、そこでは、初期化されていない領域にはアクセスできない。(コンパイルエラーになる)
すなわち、親クラス・自クラスのインスタンスフィールドから値を取得できない。
thisそのものを使用することも出来ない。
また、親クラスのコンストラクター呼び出し(super())の前に自分のクラス(子クラス)のフィールドに値を設定することが出来るようになった。
親クラスのコンストラクターからprotectedなメソッド(子クラスでオーバーライドされているメソッド)を呼び出しても、
今までは子クラスのフィールドを使用することは出来なかった。
(子クラスのフィールドが初期化されるのは、親クラスの初期化(コンストラクター呼び出し)が完了してからだったので)
Java25以降では、コンストラクター内でsuper()呼び出し前に値を設定したフィールドに関しては、親コンストラクター内で値が取得できる。
→親コンストラクター内で子クラスのフィールドの値を取得する例
this()の呼び出し前に計算を行う例。
public class BeforeThisExample {
private String key;
private String value;
public BeforeThisExample(String s) {
String key, value;
int n = s.indexOf("=");
if (n >= 0) {
key = s.substring(0, n);
value = s.substring(n + 1);
} else {
key = s;
value = null;
}
this(key, value);
}
public BeforeThisExample(String key, String value) {
this.key = key;
this.value = value;
}
}
this()・super()の呼び出しの前にthisを使うとコンパイルエラーになる。
public class BeforeThisExample { public BeforeThisExample(int n) { System.out.println(this); // NG this(); } public BeforeThisExample() { } }
Java25以降では、親クラスのコンストラクター(superメソッド)を呼び出す前に自分のクラスのフィールドを初期化することが出来る。
具体的には、「super();
」の前に「this.フィールド = 値;
」を書くことが出来る。
そして、その値は親クラスのコンストラクターの中で取得することが出来る。
abstract class Super { public Super() { // コンストラクターの中で、子クラスのフィールドの値を取得 System.out.println("Super constructor: childField1=" + getChildField1()); System.out.println("Super constructor: childField2=" + getChildField2()); } protected abstract String getChildField1(); protected abstract String getChildField2(); }
class Child extends Super { private String childField1 = "child.field1"; private String childField2; public Child() { System.out.println("Child constructor start"); this.childField2 = "child.field2 by constructor"; super(); System.out.println("Child constructor end"); } @Override protected String getChildField1() { return this.childField1; } @Override protected String getChildField2() { return this.childField2; } }
↓new Child()
の実行結果
Child constructor start Super constructor: childField1=null Super constructor: childField2=child.field2 by constructor Child constructor end
(Childの)コンストラクターの中でsuperメソッド呼び出し前に値をセットしたフィールド(上記の例のchildField2)は、親コンストラクターで値が取得できる。
フィールド定義箇所で初期値を設定したフィールド(上記の例のchildField1)の値は、親コンストラクターで取得できない。(nullが取れている)
なお、superメソッドの呼び出し前にフィールドを初期化する文を書く場合、フィールド定義箇所で初期値を指定することは出来ない。
class Child extends Super { 〜 private String childField2 = "child.field2"; public Child() { this.childField2 = "child.field2 by constructor"; // NG super(); } 〜 }
↑「Cannot assign field 'childField2' in an early construction context, because it has an initializer」というコンパイルエラー