繁体   English   中英

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

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

我想用Java包装一个类,但问题如下:

public class A {

    public A() {
       doSomething();
    }

    public void doSomething() {
    }

}

现在,当我尝试包装此类并将所有方法委托给包装器时

public class Wrapper extends A {

   private final A a;

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

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


}

当然我得到一个NPE因为'a'仍然是null,因为它是在调用overriden doSomething()方法的super()调用之后设置的。 这个问题有什么解决方案吗? 我想到的唯一一件事就是制作一个工厂方法并设置一个静态变量来保存对a的引用,但这对我来说似乎很难看。

我建议更改代码,以便在构造函数中不调用doSomething。

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

以这种方式更改您的包装器。 您不需要明确地持有A. 表达式super与您提交的相同:

class Wrapper extends A {

    public Wrapper() {
    }

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

或以其他方式提取接口并更改您的代码,如下所示:

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

避免这种情况的一种方法是通过从基类公开init方法(或任何其他名称)(如果您控制其逻辑)。 然后将调用从构造函数移动到init方法:

public class A {

    public A() {
    }

    public void init() {
        doSomething();
    }

    public void doSomething() {
    }
}

在创建类的实例之后,您应该更新代码以调用init方法,这可能是一些样板:

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

而不仅仅是

A instance = new Wrapper();

如果使用Spring和DI,则可以在xml上下文中指定init-method ,因此Spring会在解析依赖项时为您调用它。

如果doSomething方法是公共的 ,并且不接受任何参数,则可以在代码和Spring中直接使用它而不是init方法。

通常,由于遇到的问题,在构造函数中使用可覆盖的方法是反模式。 无法预测派生类如何覆盖方法,如果它们依赖于非初始化资源,那么您就遇到了麻烦。

两个小小的变化,你需要的年轻人

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

但是在constructo中调用的重写方法通常是不好的做法,并且闻起来很糟糕

暂无
暂无

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

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