繁体   English   中英

在Java中_not_调用超类构造函数的任何方法?

[英]Any way to _not_ call superclass constructor in Java?

如果我有课:

class A {
   public A() { }
}

和另一个

class B extends A {
   public B() { }
}

有没有办法让BB() 不要AA()

在Java中绝对没有办法做到这一点; 它会破坏语言规范。

JLS 12执行/ 12.5创建新类实例

在作为结果返回对新创建的对象的引用之前,处理指示的构造函数以使用以下过程初始化新对象:

  1. 为构造函数[...]分配参数
  2. 如果这个构造函数以同一个类中的另一个构造函数的显式构造函数调用开始(使用this ),那么[...]
  3. 此构造函数不以同一个类中的另一个构造函数的显式构造函数调用开头(使用this )。 如果此构造函数用于 Object 以外的类则此构造函数将以超类构造函数的显式或隐式调用开始 (使用super )。
  4. 为此类执行实例初始值设定项和实例变量初始值设定项[...]
  5. 执行此构造函数的其余部分[...]

您可以实现的最接近期望的行为是将通常在构造函数中执行的初始化委托给模板方法,然后在子类实现中重写该模板方法。 例如:

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实现作为参数。

如果您不想调用超类构造函数, 则对象模型还有其他问题。

可能的是你可以调用你选择的超类构造函数。 这可以通过显式调用超类构造函数来实现:

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

我有一个类似的要求,我需要我的子类不要通过超类的构造函数,我想要超级类的其余好处。 由于超级班也是我的,这就是我所做的。

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

不,如果可以的话,你的派生对象真的不是它从现在派生的对象吗? is-a原则将被违反。 所以如果你真的需要它,那么多态性就不是你想要的了。

需要构造每个超类,然后调用构造函数没有其他方法。

我认为唯一的方法就是弄乱字节码。
我不确定Classloader或JVM是否检查是否正在调用super() ,但是,正如Bozho写的那样,在这样做时你可能会以不一致的对象结束。

不 - 你不能这样做,为什么你还想要呢? 这会弄乱你的对象模型。

无论如何 - 我相信如果你仍然想要这样做,那么你将不得不操纵生成的字节代码....有几个库可用,可以很容易地检测字节代码。

强烈建议不要这样做......

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

不是很有用。 A的接口[不是Java关键字]表示你需要运行它的构造函数来构造它,而不是不合理地。 例外情况是构造可序列化类而不调用可序列化类的构造函数。

  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构造函数,它只调用不执行任何操作的构造函数。

Java反序列化不会调用构造函数,但似乎它基于一些内部JVM技巧。

但是,有一个框架允许您以可移植的方式执行此操作:Objenesis( http://www.theserverside.com/discussions/thread/44297.html

我最近在Spring中看到过这种情况,当使用CGLIB代理时,Spring会创建两个类实例,但构造函数只调用一次: https//stackoverflow.com/a/11583641/2557118

在Spring 4中添加了此行为:

基于CGLIB的代理类不再需要默认构造函数。 通过objenesis库提供支持,该库在线重新打包并作为Spring Framework的一部分进行分发。 使用此策略,根本不再为代理实例调用构造函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM