クラスがある場合:
class A {
public A() { }
}
と別の
class B extends A {
public B() { }
}
電話をかけB.B()
ないようにする方法はありますA.A()
か?
クラスがある場合:
class A {
public A() { }
}
と別の
class B extends A {
public B() { }
}
電話をかけB.B()
ないようにする方法はありますA.A()
か?
Java でこれを行う方法はまったくありません。言語仕様に違反します。
JLS 12 の実行 / 12.5 新しいクラス インスタンスの作成
新しく作成されたオブジェクトへの参照が結果として返される直前に、指定されたコンストラクターが処理され、次の手順を使用して新しいオブジェクトが初期化されます。
- コンストラクターの引数を割り当てます [...]
- このコンストラクターが、( を使用して) 同じクラスの別のコンストラクターの明示的なコンストラクター呼び出しで始まる場合
this
、[...]- このコンストラクターは、( を使用して) 同じクラス内の別のコンストラクターの明示的なコンストラクター呼び出しで開始されません
this
。このコンストラクターが 以外のクラス用である場合、このコンストラクターはObject
スーパークラス コンストラクターの明示的または暗黙的な呼び出し( を使用super
) で開始されます。- このクラスのインスタンス初期化子とインスタンス変数初期化子を実行します [...]
- このコンストラクターの本体の残りの部分を実行します [...]
目的の動作に最も近い方法は、コンストラクターで通常実行される初期化をテンプレート メソッドに委譲し、それをサブクラスの実装でオーバーライドすることです。例えば:
public class A {
protected Writer writer;
public A() {
init();
}
protected void init() {
writer = new FileWriter(new File("foo.txt"));
}
}
public class B extends A {
protected void init() {
writer = new PaperbackWriter();
}
}
ただし、他の人が指摘しているように、これは通常、設計に問題があることを示している可能性があり、私は通常、このシナリオでの合成アプローチを好みます。たとえば、上記のコードでは、コンストラクターを定義して、Writer
実装をパラメーターとして受け入れることができます。
スーパークラス コンストラクターを呼び出したくない場合は、オブジェクト モデルに別の問題があります。
Javaのすべてのオブジェクトは、Objectのサブクラスです(大文字の「O」を持つオブジェクト)。サブクラスのオブジェクトを作成すると、スーパークラスコンストラクターが呼び出されます。クラスが他のクラスを継承していない場合でも、暗黙的にObjectを継承しているため、Objectコンストラクターを呼び出す必要があります。したがって、super()はこの目的で呼び出されます。
あなたが意味すると仮定して
class B extends A {
public B() { }
}
その後、あなたができることを確認してください
class B extends A {
public B() {
this(abort());
}
private B(Void dummy) {
/* super(); */
}
private static Void abort() {
throw null;
}
}
あまり役に立ちません。クラスへのインターフェース[Javaキーワードではない]A
は、コンストラクターを構築するために、不当にではなく、コンストラクターを実行する必要があることを示しています。例外は、シリアル化可能なクラスは、シリアル化可能なクラスのコンストラクターを呼び出さずに構築されることです。
いいえ、できれば、派生オブジェクトは実際には現在派生しているオブジェクトではないでしょうか? is-a 原則に違反します。したがって、本当に必要な場合は、ポリモーフィズムはあなたが求めているものではありません.
すべてのスーパークラスを構築する必要があり、コンストラクターを呼び出す以外に方法はありません。
それを行う唯一の方法は、バイトコードを台無しにすることだと思います。
が呼び出されているかどうかをクラスローダーまたは JVM がチェックするかどうかはわかりませんsuper()
が、Bozho が書いているように、そうするとオブジェクトに一貫性がなくなる可能性があります。
いいえ、それはできません。なぜそれをやりたいのですか? それはあなたのオブジェクトモデルを台無しにします。
とにかく-それでもやりたいのなら、生成されたバイトコードを操作する必要があると思います....バイトコードを簡単に計測できるライブラリがいくつかあります。
それをしないことを強く提案します...
子クラスがスーパークラスのコンストラクターを通過しないようにする必要があるという同様の要件があり、スーパークラスの残りの利点が必要でした。スーパークラスも私のものなので、これが私がしたことです。
class SuperClass {
protected SuperClass() {
init();
}
// Added for classes (like ChildClassNew) who do not want the init to be invoked.
protected SuperClass(boolean doInit) {
if (doInit)
init();
}
//
}
class ChildClass1 extends SuperClass {
ChildClass1() {
// This calls default constructor of super class even without calling super() explicitly.
// ...
}
// ....
}
class ChildClass2 extends SuperClass {
ChildClass2() {
// This calls default constructor of super class even without calling super() explicitly.
// ...
}
// ....
}
class ChildClassNew extends SuperClass {
ChildClassNew() {
/*
* This is where I didn't want the super class' constructor to
* be invoked, because I didn't want the SuperClass' init() to be invoked.
* So I added overloaded the SuperClass' constructor where it diesn;t call init().
* And call the overloaded SuperClass' constructor from this new ChildClassNew.
*/
super(false);
//
// ...
}
// ....
}
別のポスターで指摘されているように、B は A を拡張しないため、とにかく A のコンストラクターは呼び出されません。
Java でこれを行う方法はありません。
おそらく、次のようにして、やりたいことを同等に達成できます。
a) 階層の各クラスに、引数を使用してスーパークラスのコンストラクターを呼び出す一意のシグネチャを持つコンストラクターを含めます。たとえば、クラス「Noop」とそれを引数として取るコンストラクターを宣言します。
public class NoOp {
}
public class class1 {
class1() {
System.out.println("class1() called");
}
class1(String x, String y) {
System.out.println("class1(String, String) called");
}
class1(NoOp x) {
System.out.println("class1(NoOp) called");
}
}
public class class2 extends class1 {
class2() {
System.out.println("class2() called");
}
class2(String x, String y) {
System.out.println("class2(String, String) called");
}
class2(NoOp x) {
super(x);
System.out.println("class2(NoOp) called");
}
}
public class class3 extends class2 {
class3() {
System.out.println("class3() called");
}
class3(String x, String y) {
super(new NoOp());
System.out.println("class3(String, String) called");
}
class3(NoOp x) {
super(x);
System.out.println("class3(NoOp) called");
}
public static void main(String args[]) {
class3 x = new class3("hello", "world");
}
}
これを実行すると、出力が得られます
class1(NoOp) called
class2(NoOp) called
class3(String, String) called
したがって、事実上、何もしないコンストラクターのみを呼び出す class3 コンストラクターを作成しました。