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

时间:2010-06-03 15:58:07

标签: java oop constructor super

如果我有课:

class A {
   public A() { }
}

和另一个

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

有没有办法让B.B() 来致电A.A()

13 个答案:

答案 0 :(得分:27)

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

JLS 12 Execution / 12.5 Creation of New Class Instances

  

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

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

答案 1 :(得分:19)

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

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

答案 2 :(得分:8)

如果您不想调用超类构造函数,对象模型中存在 else 错误。

答案 3 :(得分:1)

可能性是您可以调用您选择的超类构造函数。通过将超类构造函数显式调用为:

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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

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

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

答案 8 :(得分:0)

java中的每个对象都是Object的子类(具有大写“O”的对象)。当您创建子类的对象时,将调用超类构造函数。即使你的类不是其他任何类,隐式地它继承了Object,因此必须调用Object构造函数。因此,为此目的调用了super()。

答案 9 :(得分:0)

假设你的意思

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关键字]表示你需要运行它的构造函数来构造它,而不是不合理地。例外情况是构造可序列化类而不调用可序列化类的构造函数。

答案 10 :(得分:0)

  1. 正如另一张海报所指出的那样,B不会扩展A,所以无论如何它都不会调用A的构造函数。

  2. 在Java中无法做到这一点。

  3. 您可以按照以下方式等效地完成您想要做的事情:

  4. 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构造函数。

答案 11 :(得分:0)

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

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

答案 12 :(得分:0)

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的一部分。有了这个   策略,根本没有为代理实例调用构造函数   了。