14

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

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
  }
}

谢谢!

4

4 回答 4

18

正如@Voo 所说,

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

来自Effective Java 2nd Edition,第 17 项:设计和记录继承,否则禁止它:

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

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

构造函数必须只调用最终或私有的方法

您可以使用静态工厂方法来解决必须从Bar class.

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

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

所以,你去有界面:

public interface Foo {
     void doFoo();
}

和实施:

public class FooImpl implements Foo {
   @Override
   public void doFoo() {
   //.. Do important code
   }
}

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

  • 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;
    }
}

我的老板说:“声纳警告是关于症状的,而不是关于疾病的。能治好病最好。” !

于 2015-10-08T20:02:24.233 回答
6

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

public final void doFoo() { }

于 2012-04-26T16:04:45.467 回答
0

您的 IDE 会告诉您这一点,因为它可能不安全。您可以提供任何实现或 doFoo 并在启动时将所有 Bar 对象设置为不同的东西。在大多数情况下,这似乎是一个糟糕的设计选择。

似乎您在构造函数中使用了策略模式。在构造函数中使用策略或任何其他可覆盖的行为是不明智的。在其他地方使用它。

于 2012-04-26T16:05:20.967 回答
0

您看到的错误来源是PMD(在此处搜索“overr”),并且在再次构建示例时,此版本的 PMD(4.2.6)不会触发此警告。Sonar 只是集成了 PMD、Checkstyle 等工具,并提供了一个概览。因此,请检查您使用的是哪个版本的声纳(和 PMD)。

您可以在 Sonar 中查看:Sonar > Quality Profiles > Search for "overr"应该突出显示您正在使用的规则。

在 Sonar 中,您可以检查您正在使用的 PMD 版本。转到Sonar > Configuration > Update Center,然后查看您正在使用的 PMD 版本。

于 2013-07-24T11:43:49.607 回答