これらのクラスがどのようにコンパイルされるかをテストしましょう。
public class Test1 {
private Scanner in;
public Test1() {
in = new Scanner(System.in);
}
}
と
public class Test2 {
private Scanner in = new Scanner(System.in);
public Test2() {
}
}
使えばわかりjavap -c Test1
ます
Compiled from "Test1.java"
public class Test1 {
public Test1();
Code:
0: aload_0
1: invokespecial #10 // Method java/lang/Object."<init>":()V
4: aload_0
5: new #12 // class java/util/Scanner
8: dup
9: getstatic #14 // Field java/lang/System.in:Ljava/io/InputStream;
12: invokespecial #19 // Method java/util/Scanner."<init>":(Ljava/io/InputStream;)V
15: putfield #22 // Field in:Ljava/util/Scanner;
18: return
}
そして、それを使用するとTest2
、
Compiled from "Test2.java"
public class Test2 {
public Test2();
Code:
0: aload_0
1: invokespecial #10 // Method java/lang/Object."<init>":()V
4: aload_0
5: new #12 // class java/util/Scanner
8: dup
9: getstatic #14 // Field java/lang/System.in:Ljava/io/InputStream;
12: invokespecial #19 // Method java/util/Scanner."<init>":(Ljava/io/InputStream;)V
15: putfield #22 // Field in:Ljava/util/Scanner;
18: return
}
ご覧のとおりin
、クラスのフィールドの初期化はTest2
、コンストラクターの開始時にコンパイラーによって自動的に移動されました。
実際、このコードはそのクラスの各コンストラクターの開始時 (もしあれば呼び出しの直後super()
) に移動されるため、唯一の違いは、コンストラクターがほとんどない場合、in
コンストラクターのすべてで行うのではなく、コンストラクターの外側の 1 つの場所でフィールドを初期化できることです。 .
ただし、コンストラクターに渡された引数に応じてフィールドを初期化したい場合は、コンストラクター ブロックでそれを行う必要があります。