如何修复"构造函数调用可覆盖的方法"

use*_*479 13 java constructor overriding

我有以下设置,它给我一条消息,指出"构造函数调用Overridable方法".我知道这种情况正在发生,但我的问题是如何修复它以便代码仍然有效并且消息消失了.

public interface Foo{
   void doFoo();
}
public class FooImpl implements Foo{
 @Override{
 public void doFoo(){
    //.. Do important code
 }
}
public class Bar{
  private FooImpl fi;
  public Bar(){
    fi = new FooImpl();
    fi.doFoo(); // The message complains about this line
  }
}
Run Code Online (Sandbox Code Playgroud)

谢谢!

Jes*_*rce 16

正如@Voo所说,

你的问题是关于在已经完全构造的对象上调用虚方法.在构造对象上调用虚方法的众所周知的缺点是众所周知的,但这里不适用

Effective Java 2nd Edition,Item 17:继承的设计和文档,或者禁止它:

为了允许继承,类必须遵守一些限制.构造函数不得直接或间接调用可覆盖的方法.如果违反此规则,将导致程序失败.超类构造函数在子类构造函数之前运行,因此在子类构造函数运行之前将调用子类中的重写方法.如果重写方法依赖于子类构造函数执行的任何初始化,则该方法将不会按预期运行.

在对象构造期间调用可覆盖的方法可能导致使用未初始化的数据,从而导致运行时异常或意外结果.

构造函数必须只调用final或private方法

您可以使用静态工厂方法来解决您必须从中创建对象的问题Bar class.

有效的Java,第1项:考虑静态工厂方法而不是构造函数

类允许客户端获取自身实例的常规方法是提供公共构造函数.还有另一种技术应该是每个程序员工具包的一部分.类可以提供公共静态工厂方法,它只是一个返回类实例的静态方法.

所以,你去拥有界面:

public interface Foo {
     void doFoo();
}
Run Code Online (Sandbox Code Playgroud)

和实施:

public class FooImpl implements Foo {
   @Override
   public void doFoo() {
   //.. Do important code
   }
}
Run Code Online (Sandbox Code Playgroud)

要使用工厂方法创建类,可以通过以下方式工作:

  • 使用接口来定义类的变量private Foo fi而不是private FooImpl fi,使用具体类型的接口是良好封装和松散耦合代码的关键.

  • 使您的默认构造函数为私有,以防止您的类在外部实例化.

    private Bar(){//防止实例化}

  • 删除所有调用以覆盖构造函数中存在的方法.

  • 创建静态工厂方法

最后,你得到一个Bar工厂方法的类,如:

public class Bar {
    private Foo fi;

    private Bar() {// Prevents instantiation
        fi = new FooImpl();
    }

    public static Bar createBar() {
        Bar newBar = new Bar();
        newBar.fi.doFoo(); 

        return newBar;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的老板说:"声纳警告是关于症状,而不是疾病.你最好能治疗这种疾病."!


Pab*_*blo 6

如果以后不需要覆盖该方法,则可以将doFoo声明为final:

public final void doFoo() { }