サブクラスを定義すると、スーパークラスからコンストラクターが継承されません。デフォルトのスーパークラス コンストラクター以外の場合は、各サブクラス コンストラクターで明示的にスーパークラス コンストラクターを呼び出す必要があります。(つまり、特に、基本クラスにデフォルト コンストラクターがない場合、すべての子クラス コンストラクターがスーパークラス コンストラクターを明示的に呼び出す必要がある子クラスもありません。また、子クラスは単にコンパイラによって生成されたデフォルト コンストラクターを持つことはできません。これには例外が 1 つあります。以下の[*]を参照してください。)
コンストラクターを継承すると、あらゆる種類の問題が発生する可能性があります。次のようなものを想像してください。
class Base {
private int mId;
public Base(int id) {
mId = id;
}
. . .
}
ここで、never であることを確認したい 2 番目の属性 (タグ) を持つクラスを派生させたいと考えていますnull
。したがって、次のように記述します。
class Derived extends Base {
private Object mTag;
public Derived(Object tag, int id) {
super(id);
if (tag == null) {
throw new IllegalArgumentException("tag cannot be null");
}
mTag = tag;
}
. . .
}
Derived
次のようなインスタンスを作成することを想像してください。
Derived derived = new Derived(3);
コンストラクターが継承された場合、これはおそらく合法です。それはどういう意味ですか?1 つには、mTag
デフォルト値の に設定されますnull
。のすべてのインスタンスにnull 以外のタグが必要Derived
であるという規則を強制する方法はありません。Derived
Java は、もう少し型付けが必要になる代わりに、コンストラクターの継承を正確に除外して、各クラスがそのインスタンスの作成方法を完全に制御できるようにします。
[*]コンパイラがデフォルト以外のコンストラクタを自動的に生成するケースが 1 つあります。Base
上記のクラスと次のコードを検討してください。
Base foo = new Base(3) {
. . . // some extended functionality
};
現在foo
、 の無名サブクラスに初期化されていますBase
。参照しやすいように、このサブクラスを と呼びましょうBase$Anon
。コンパイラは、次と同等のコードを生成します。
class Base$Anon extends Base {
Base$Anon(int id) {
super(id);
}
. . . // some extended functionality
}
Base foo = new Base$Anon(3);
これは、独自のコンストラクターを指定しない場合に、コンパイラーがデフォルト以外のコンストラクターを生成する唯一のケースです。実際、言語構文では、匿名クラスのコンストラクターを宣言することさえできません。生成するコンパイラに依存する必要があります。