web-dev-qa-db-ja.com

Javaでスーパークラスコンストラクターを呼び出さない方法はありますか?

クラスがある場合:

_class A {
   public A() { }
}
_

と別の

_class B extends A {
   public B() { }
}
_

B.B()notを取得してA.A()を呼び出す方法はありますか?

Javaでこれを行う方法は絶対にありません。言語仕様に違反します。

JLS12実行/12.5新しいクラスインスタンスの作成

新しく作成されたオブジェクトへの参照が結果として返される直前に、示されたコンストラクターが処理され、次の手順を使用して新しいオブジェクトが初期化されます。

  1. コンストラクターの引数を割り当てます[...]
  2. このコンストラクターが、同じクラス内の別のコンストラクターの明示的なコンストラクター呼び出しで始まる場合(thisを使用)、[...]
  3. このコンストラクターは、同じクラス内の別のコンストラクターの明示的なコンストラクター呼び出しで始まりません(thisを使用)。 このコンストラクターがObject以外のクラス用である場合、このコンストラクターはスーパークラスコンストラクターの明示的または暗黙的な呼び出しsuperを使用)。
  4. このクラスのインスタンス初期化子とインスタンス変数初期化子を実行します[...]
  5. このコンストラクターの本体の残りを実行します[...]
30

目的の動作に最も近い方法は、コンストラクターで通常実行される初期化をテンプレートメソッドに委任することです。テンプレートメソッドは、サブクラスの実装でオーバーライドします。例えば:

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実装をパラメーターとして受け入れるようにコンストラクターを定義できます。

20
Adamski

スーパークラスコンストラクターを呼び出したくない場合は、オブジェクトモデルに何かelse問題があります。

7
Dolph

Javaの逆シリアル化はコンストラクターを呼び出しませんが、内部のJVMトリックに基づいているようです。

ただし、移植可能な方法でそれを行うことを可能にするフレームワークがあります:Objenesis( http://www.theserverside.com/discussions/thread/44297.html

最近Springでこれを見ましたが、CGLIBプロキシを使用すると、Springは2つのクラスインスタンスを作成しますが、コンストラクターは1回だけ呼び出されます: https://stackoverflow.com/a/11583641/2557118

この動作はSpring4で追加されました。

CGLIBベースのプロキシクラスは、デフォルトのコンストラクタを必要としなくなりました。サポートは、インラインで再パッケージ化され、SpringFrameworkの一部として配布されるobjenesisライブラリを介して提供されます。この戦略では、プロキシインスタンスに対してコンストラクターはまったく呼び出されなくなりました。

1
Mihai

可能性としては、選択したスーパークラスコンストラクターを呼び出すことができます。これは、スーパークラスコンストラクターを次のように明示的に呼び出すことで可能になります。

super(para_1, para_2,........);

class BaseA {
    BaseA(){
        System.out.println("This is BaseA");
    }
    BaseA(int a){
        System.out.println("This is BaseA a");
    }


}

class A extends BaseA {

    A(){
        super(5);
        System.out.println("This is A");
    }

    public static void main(String[] args) {
        A obj=new A();

    }
}


Output will be:
This is BaseA a
This is A
1
Vikas Kumar

いいえ、できません。とにかくやりたいのはなぜですか。それはあなたのオブジェクトモデルを台無しにするでしょう。

とにかく-それでもやりたいのなら、生成されたバイトコードを操作する必要があると思います...バイトコードを簡単にインストルメント化できるライブラリがいくつかあります。

それをしないことを強くお勧めします...

0
arcamax

JavaのすべてのオブジェクトはObjectのサブクラスです(大文字の「O」を持つオブジェクト)。サブクラスのオブジェクトを作成すると、スーパークラスコンストラクターが呼び出されます。クラスが継承していなくても他のクラスは、暗黙的にObjectを継承しているため、Objectコンストラクターを呼び出す必要があります。したがって、この目的でsuper()が呼び出されます。

0
srikanth

いいえ、できれば、派生オブジェクトは実際にはそれが今から派生しているオブジェクトではないでしょうか? is-原則に違反します。したがって、本当にそれが必要な場合、ポリモーフィズムはあなたが求めているものではありません。

0
Blindy

あなたが意味すると仮定して

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;
     }
}

あまり役に立ちません。クラスAへのインターフェース[not Java keyword]]は、コンストラクターを構築するために、不当にではなく、コンストラクターを実行する必要があることを示しています。例外は、シリアル化可能なクラスがなしで構築されることです。シリアル化可能なクラスのコンストラクターを呼び出します。

すべてのスーパークラスneedsを構築する必要があり、コンストラクターを呼び出す方法は他にありません。

0
Andreas_D
  1. 別の投稿者が指摘しているように、BはAを拡張しないため、とにかくAのコンストラクターを呼び出すことはありません。

  2. Javaでこれを行う方法はありません。

  3. あなたはおそらくあなたがしたいことを次のように同等に達成することができます:

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コンストラクターを作成しました。

0
Larry Watanabe

それを行う唯一の方法は、バイトコードをいじることだと思います。
クラスローダーまたはJVMがsuper()が呼び出されているかどうかを確認するかどうかはわかりませんが、Bozhoが書いたように、そうするとオブジェクトに一貫性がなくなる可能性があります。

0
user85421

子クラスがスーパークラスのコンストラクターを通過しないようにする必要があるという同様の要件があり、スーパークラスの残りの利点が必要でした。スーパークラスも私のものなので、これが私がしたことです。

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);
        // 
        // ...
    }
    // ....
}
0
John Gummadi