Java FAQ:スーパークラスの引数なしコンストラクタがないとコンパイルエラーになる場合

Java FAQ:S010 Q-03

話がちょっとややこしい?
と、思ったのは、デフォルトコンストラクタを勘違いしていたからのようだ。

「クラスの定義にコンストラクタを一つも記述しなかった場合、コンパイラによって自動的に引数なしのコンストラクタが生成されます。」の「一つも記述しなかった場合」を分かっていなかった。

class C2008041411 {
    //C2008041411() {
    //    System.out.println("C2008041411");
    //}

    C2008041411(String str) {
        System.out.println("C2008041411: " + str);
    }
}

class C2008041412 extends C2008041411 {
    C2008041412(String str) {
        System.out.println("C2008041412: " + str);
    }
}

public class C2008041410 {
    public static void main(String[] args) {
        new C2008041412("foo");
    }
}

コンパイルすると、以下のエラー。
エラーが分かりにくいけど、「コンストラクタ C2008041411() が見つからない」ということなんだろう。

C2008041410.java:13: シンボルを解釈処理できません。
シンボル: コンストラクタ C2008041411  ()
位置    : C2008041411 の クラス
    C2008041412(String str) {
                            ^
エラー 1 個


スーパークラスの引数なしコンストラクタを定義

class C2008041421 {
    C2008041421() {
        System.out.println("C2008041421");
    }

    C2008041421(String str) {
        System.out.println("C2008041421: " + str);
    }
}

class C2008041422 extends C2008041421 {
    C2008041422(String str) {
        System.out.println("C2008041422: " + str);
    }
}

public class C2008041420 {
    public static void main(String[] args) {
        new C2008041422("foo");
    }
}

で、

C2008041421
C2008041422: foo

C2008041422 に対し、javap -c を実行

Compiled from C2008041420.java
class C2008041422 extends C2008041421 {
    C2008041422(java.lang.String);
}

Method C2008041422(java.lang.String)
   0 aload_0
   1 invokespecial #1 <Method C2008041421()>
   4 getstatic #2 <Field java.io.PrintStream out>
   7 new #3 <Class java.lang.StringBuffer>
  10 dup
  11 invokespecial #4 <Method java.lang.StringBuffer()>
  14 ldc #5 <String "C2008041422: ">
  16 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>
  19 aload_1
  20 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>
  23 invokevirtual #7 <Method java.lang.String toString()>
  26 invokevirtual #8 <Method void println(java.lang.String)>
  29 return

確かに、「Method C2008041422(java.lang.String)」の中で「1 invokespecial #1 」のように「C2008041421()」を呼んでいるようだ(明示的に書いていないのに)。


対処法の一つ「サブクラスの別のコンストラクタを呼び出す」の

public LazyPerson() {
  this("なまけもの");
}

public LazyPerson(String name) {
  super(name);
}

は、「super(name);」としていないとダメ。ということは、別の解決法「スーパクラスの別のコンストクタを呼び出す」を併用しているような気もする。