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

时间:2014-04-10 09:15:35

标签: java inheritance wrapper

我想用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的引用,但这对我来说似乎很难看。

4 个答案:

答案 0 :(得分:1)

我建议更改代码,以便在构造函数中不调用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();
   }
}

答案 1 :(得分:1)

以这种方式更改您的包装器。您不需要明确地持有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();
}

答案 2 :(得分:0)

要避免这种情况的方法是从基类中公开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方法。

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

答案 3 :(得分:0)

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

 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中调用的重写方法通常是不好的做法,并且味道很糟糕