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

Posted

技术标签:

【中文标题】在Java中_not_调用超类构造函数的任何方法?【英文标题】:Any way to _not_ call superclass constructor in Java? 【发布时间】:2011-02-27 09:38:04 【问题描述】:

如果我有课:

class A 
   public A()  

还有一个

class B extends A 
   public B()  

有没有办法让B.B()打电话给A.A()

【问题讨论】:

你的意思是class B extends A ?顺便说一句:这些不是好的类名——它们看起来像泛型参数。 无论如何你都没有从 B 调用 A 的构造函数,B 不是从 A 继承的 谢谢大家。我只是想从不同的包中扩展别人的课程。我只重写了部分内容。见:***.com/questions/2962491/…谢谢!米莎 如果你发现自己需要这样做,那么你不需要继承,你需要组合。 【参考方案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

【讨论】:

【参考方案2】:

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

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

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

此行为是在 Spring 4 中添加的:

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

【讨论】:

【参考方案3】:

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

JLS 12 Execution / 12.5 Creation of New Class Instances

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

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

【讨论】:

@reevesy 链接已损坏【参考方案4】:

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

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

【讨论】:

“有效的 Java 第 2 版,第 17 项:设计和记录继承,否则禁止它:构造函数不得直接或间接调用可覆盖的方法。” 我并不是说这是一件好事——我只是说你会这样做。【参考方案5】:

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

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

【讨论】:

【参考方案6】:

    正如另一位发帖者所指出的,B 不会扩展 A,因此它不会调用 A 的构造函数。

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

    您可能可以等效地完成您想做的事情,如下所示:

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 构造函数,它只调用不做任何事情的构造函数。

【讨论】:

【参考方案7】:

假设你的意思

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

【讨论】:

【参考方案8】:

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

【讨论】:

【参考方案9】:

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

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

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

【讨论】:

【参考方案10】:

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

【讨论】:

毫无疑问,但在我有时间解决这个问题之前,我需要解决它。 在类仅用作类型标识符而不提供功能的情况下,例如空对象模式,试图避免调用层次结构上的构造函数的开销有什么问题?!跨度> 这不是答案【参考方案11】:

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

【讨论】:

【参考方案12】:

每个超类都需要被构造,除了调用构造函数之外别无他法。

【讨论】:

【参考方案13】:

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

【讨论】:

以上是关于在Java中_not_调用超类构造函数的任何方法?的主要内容,如果未能解决你的问题,请参考以下文章

在 python 中使用不同的参数调用超类构造函数

2016年4月2日_JAVA学习笔记_下午

JavaSE复习_3 继承

Java基础-继承

scala_类的继承

在派生类的构造函数中初始化超类