有什么方法可以_不_调用Java中的超类构造函数吗?

发布于 2024-09-03 17:07:18 字数 223 浏览 9 评论 0原文

如果我有一个类:

class A {
   public A() { }
}

还有另一个类,

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

有什么方法可以让 BB() 调用 AA() 吗?

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() not to call A.A()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

天暗了我发光 2024-09-10 17:07:18

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

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

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

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

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

JLS 12 Execution / 12.5 Creation of New Class Instances

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 than Object, 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 [...]
多情出卖 2024-09-10 17:07:18

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

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

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 approach in this scenario; for example in the above code you could define the constructor to accept a Writer implementation as a parameter.

苦妄 2024-09-10 17:07:18

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

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

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

Spring 4 中添加了此行为:

基于 CGLIB 的代理类不再需要默认构造函数。
通过重新打包的 objenesis 库提供支持
作为 Spring 框架的一部分内联和分发。有了这个
策略,根本没有为代理实例调用构造函数
不再了。

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

However, there is a framework that allows you to do that in a portable manner: 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

This behavior is added in 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.

爱要勇敢去追 2024-09-10 17:07:18

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

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

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
去了角落 2024-09-10 17:07:18

不,如果可以的话,您的派生对象就不会真正是它现在派生的对象,不是吗? is-a 原则将被违反。因此,如果您确实需要它,那么多态性就不是您所追求的。

No and if you could, your derived object wouldn't really be the object it's deriving from now would it? The is-a principle would be violated. So if you really need it, then polymorphism isn't what you're after.

北方。的韩爷 2024-09-10 17:07:18

每个超类都需要被构造,除了调用构造函数之外没有其他方法。

Every superclass needs to be constructed and there is no other way then calling a constructor.

靖瑶 2024-09-10 17:07:18

我认为唯一的方法就是弄乱字节码。
我不确定类加载器或 JVM 是否检查 super() 是否被调用,但是,正如 Bozho 所写,这样做时您可能会得到不一致的对象。

I think the only way to do it is messing up with the byte-code.
I'm not sure if the Classloader or the JVM checks if super() is being called, but, as Bozho wrote, you probably would end with inconsistent objects when doing so.

幸福%小乖 2024-09-10 17:07:18

不——你做不到,为什么你还要这么做呢?这会弄乱你的对象模型。

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

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

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...

慢慢从新开始 2024-09-10 17:07:18

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

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.

抱猫软卧 2024-09-10 17:07:18

假设你的意思是

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 关键字] 表示您需要运行其构造函数才能构造它,这并非没有道理。例外情况是,在不调用可序列化类的构造函数的情况下构造可序列化类。

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 A says 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.

神仙妹妹 2024-09-10 17:07:18
  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 构造函数,该构造函数仅调用不执行任何操作的构造函数。

  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:

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:

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.

对你而言 2024-09-10 17:07:18

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

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

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);
        // 
        // ...
    }
    // ....
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文