简体   繁体   English

Java包装器:覆盖超级构造函数中调用的方法

[英]Java wrapper: overriding a method called in the super constructor

I want to wrap a class in Java but the problem is as follows: 我想用Java包装一个类,但问题如下:

public class A {

    public A() {
       doSomething();
    }

    public void doSomething() {
    }

}

Now when I try to wrap this class and delegate all methods to the wrapper 现在,当我尝试包装此类并将所有方法委托给包装器时

public class Wrapper extends A {

   private final A a;

   public Wrapper(A a) {
      super();
      this.a = a;
   }

   @Override
   public void doSomething() {
      this.a.doSomeThing();
   }


}

of course I get a NPE as 'a' is still null as it is set after the super()-call which calls the overriden doSomething() method. 当然我得到一个NPE因为'a'仍然是null,因为它是在调用overriden doSomething()方法的super()调用之后设置的。 Is there any solution for this problem? 这个问题有什么解决方案吗? The only thing that came to my mind was making a factory method and setting a static variable holding the reference to a but this seems ugly to me. 我想到的唯一一件事就是制作一个工厂方法并设置一个静态变量来保存对a的引用,但这对我来说似乎很难看。

I'd recommend changing the code so that doSomething is not called in the constructor. 我建议更改代码,以便在构造函数中不调用doSomething。

Alternatively split A into an interface and implementation Wrapper implements the interface and does not inherit from A 或者将A拆分为接口,实现Wrapper实现接口,不从A继承

public interface IA {

    public void doSomething() {
    }

}
public class A implements IA {

    public A() {
       doSomething();
    }

    public void doSomething() {
    }

}


public class Wrapper implements IA {

   private final IA a;

   public Wrapper(IA a) {
      this.a = a;
      doSomething();
   }

   @Override
   public void doSomething() {
      a.doSomeThing();
   }
}

Change your Wrapper this way. 以这种方式更改您的包装器。 You do not need to hold A explicitly. 您不需要明确地持有A. The expression super is the same as your filed: 表达式super与您提交的相同:

class Wrapper extends A {

    public Wrapper() {
    }

    @Override public void doSomething() {
        super.doSomething();
    }
}

Or otherwise extract an interface and change your code like this: 或以其他方式提取接口并更改您的代码,如下所示:

class Wrapper implements AA {

    private final AA child;

    public Wrapper(AA child) {
        this.child = child;
    }

    @Override public void doSomething() {
        child.doSomething();
    }
}

class A implements AA {

    public A() {
       doSomething();
    }

    @Override public void doSomething() {}
}

interface AA {
    public void doSomething();
}

A way for this to be avoided is by exposing an init method (or any other name) from your base class (if you are in control of its logic). 避免这种情况的一种方法是通过从基类公开init方法(或任何其他名称)(如果您控制其逻辑)。 Then move the call from the constructor to the init method: 然后将调用从构造函数移动到init方法:

public class A {

    public A() {
    }

    public void init() {
        doSomething();
    }

    public void doSomething() {
    }
}

You should update your code to call the init method after making an instance of the class, which may be a bit of boilerplate: 在创建类的实例之后,您应该更新代码以调用init方法,这可能是一些样板:

A instance = new Wrapper();
instance.init();

instead of just 而不仅仅是

A instance = new Wrapper();

If you use Spring and DI, you can specify an init-method in the xml context, so Spring will call it for you when it resolves the dependency. 如果使用Spring和DI,则可以在xml上下文中指定init-method ,因此Spring会在解析依赖项时为您调用它。

In case the doSomething method is public , and accepts no arguments, you can use it directly instead of the init method both in code and with Spring. 如果doSomething方法是公共的 ,并且不接受任何参数,则可以在代码和Spring中直接使用它而不是init方法。

In general, use of overridable methods in a constructor is an anti-pattern, due to the problem you have encountered. 通常,由于遇到的问题,在构造函数中使用可覆盖的方法是反模式。 There is no way to predict how a derived class will override the methods and if they rely on non-initialized resources, then you are in trouble. 无法预测派生类如何覆盖方法,如果它们依赖于非初始化资源,那么您就遇到了麻烦。

two small changes, young one you need 两个小小的变化,你需要的年轻人

 public class Wrapper extends A {

       private final A a;

       public Wrapper(A a) {
          super();
          this.a = a;

        //this will execute method doSomething wrom Wrapper class after variable a is set
          doSomething(); 

       }

       @Override
       public void doSomething() {
    //this will prevent to call metod from superclass constructor, bit risky thou
         if (a!=null)       
          this.a.doSomething();
       }
    }

but overriding methods which are called in constructo is generally bad practice and smells terrible 但是在constructo中调用的重写方法通常是不好的做法,并且闻起来很糟糕

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

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