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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2967662/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 23:44:37  来源:igfitidea点击:

Any way to _not_ call superclass constructor in Java?

javaoopconstructorsuper

提问by Миша Кошелев

If I have a class:

如果我有一堂课:

class A {
   public A() { }
}

and another

而另一个

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

is there any way to get B.B()notto call A.A()?

有什么办法可以B.B()打电话A.A()吗?

回答by polygenelubricants

There is absolutely no way to do this in Java; it would break the language specification.

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

JLS 12 Execution / 12.5 Creation of New Class Instances

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

Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:

  1. Assign the arguments for the constructor [...]
  2. If this constructor begins with an explicit constructor invocation of another constructor in the same class (using this), then [...]
  3. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other thanObject, then this constructor will begin with an explicit or implicit invocation of a superclass constructor(using super).
  4. Execute the instance initializers and instance variable initializers for this class [...]
  5. Execute the rest of the body of this constructor [...]

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

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

回答by Adamski

The closest you can achieve to the desired behaviour is to delegate initialisation normally performed in the constructor to a template method, which you then override in your subclass implementation. For example:

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

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

However, as other people have noted this can typically indicate a problem with your design and I typically prefer the composition approachin this scenario; for example in the above code you could define the constructor to accept a Writerimplementation as a parameter.

但是,正如其他人所指出的,这通常表明您的设计存在问题,我通常更喜欢这种情况下的组合方法;例如在上面的代码中,您可以定义构造函数以接受一个Writer实现作为参数。

回答by Dolph

If you don't want to call the superclass constructor, there is something elsewrong with your object model.

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

回答by Mihai

Java deserialisation doesn't call the constructor, but it seems that it is based on some internal JVM tricks.

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

However, there is a framework that allows you to do that in a portable manner: Objenesis (http://www.theserverside.com/discussions/thread/44297.html)

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

I've seen this recently in Spring, when using CGLIB proxies, Spring creates two class instances, but the constructor is called only once: https://stackoverflow.com/a/11583641/2557118

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

This behavior is added in Spring 4:

此行为在 Spring 4 中添加:

CGLIB-based proxy classes no longer require a default constructor. Support is provided via the objenesis library which is repackaged inline and distributed as part of the Spring Framework. With this strategy, no constructor at all is being invoked for proxy instances anymore.

基于 CGLIB 的代理类不再需要默认构造函数。支持是通过 objenesis 库提供的,该库被重新打包内联并作为 Spring 框架的一部分分发。使用此策略,不再为代理实例调用任何构造函数。

回答by Vikas Kumar

The possibility is that you can call the super class constructor of your choice. That is possible by calling the super class constructor explicitly as :

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

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

回答by arcamax

Nope - you cannot do it and why would you want to do it anyway? That would mess up your object model.

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

Anyways - i believe if you still want to do it and then you would have to manipulate the generated byte code.... there are a couple of libraries available that make it easy to instrument the byte code.

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

Strongly suggest against doing it...

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

回答by srikanth

Every object in java is a subclass of Object (object with a capital 'O'). when you create an object of a subclass the super class constructor is invoked. Even if your class is not inhereting anyother class, implicitly it is inheriting Object, so the Object constructor has to be called. So super() is invoked for this purpose.

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

回答by Tom Hawtin - tackline

Assuming you mean

假设你的意思是

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

then sure you can

那么你肯定可以

class B extends A {
     public B() {
         this(abort());
     }
     private B(Void dummy) {
         /* super(); */
     }
     private static Void abort() {
         throw null;
     }
}

Not very useful. The interface [not Java keyword] to class Asays that you need to run its constructor in order to construct it, not unreasonably. The exception is that serialisable classes are constructed without calling the constructors of the serialisable classes.

不是很有用。class 的接口 [不是 Java 关键字]A表示您需要运行其构造函数才能构造它,这并非不合理。例外是可序列化类是在不调用可序列化类的构造函数的情况下构造的。

回答by Larry Watanabe

  1. As pointed out by another poster, B doesn't extend A, so it won't call A's constructor anyways.

  2. There is no way to do this in Java.

  3. You can probably accomplish equivalently what you want to do as follows:

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

  2. 在 Java 中没有办法做到这一点。

  3. 您可能可以按如下方式完成您想要做的事情:

a) in each class of your hierarchy, include a constructor with a unique signature that calls the superclass's constructor with its arguments. For example, declare a class "Noop" and a constructor that takes that as an argument:

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

If you run this you will get the output

如果你运行这个你会得到输出

class1(NoOp) called
class2(NoOp) called
class3(String, String) called

So, effectively you have created a class3 constructor that only calls constructors that don't do anything.

因此,实际上您已经创建了一个 class3 构造函数,它只调用不执行任何操作的构造函数。

回答by John Gummadi

I had a similar requirement where I needed my child class NOT to go through the super class' constructor, and I wanted the rest of the benefits of the super class. Since super class is also mine, here's what I did.

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

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