Java “如何修复”;构造函数调用可重写方法;

Java “如何修复”;构造函数调用可重写方法;,java,constructor,overriding,Java,Constructor,Overriding,我有以下设置,它给了我一条消息,说明“构造函数调用可重写的方法”。我知道这正在发生,但我的问题是如何修复它,使代码仍然有效,消息消失 public interface Foo{ void doFoo(); } public class FooImpl implements Foo{ @Override{ public void doFoo(){ //.. Do important code } } public class Bar{ private FooImpl fi;

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

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

谢谢

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

public final void doFoo(){

}

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


似乎您正在构造函数中使用策略模式。在构造函数中使用策略或任何其他过度行为是不明智的。请在其他地方使用它。

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

您可以在Sonar中查看:
Sonar>Quality Profiles>搜索“overr”
应突出显示您正在使用的规则

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

正如@Voo所说

您的问题是关于对已存在的对象调用虚拟方法 完全构造的对象。众所周知的通话失败 to构造对象上的虚拟方法是众所周知的,但不是 在这里申请

来自,第17项:继承的设计和文档,否则禁止:

类还必须遵守一些限制才能允许 遗产构造函数不能调用可重写的方法, 直接或间接地。如果违反此规则,程序将失败 结果。超类构造函数在子类之前运行 构造函数,因此将调用子类中的重写方法 在子类构造函数运行之前。如果重写方法 取决于子类构造函数执行的任何初始化, 该方法的行为将不符合预期

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

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

您可以使用静态工厂方法来解决必须从
条形类创建对象的问题

<强>有效java,项目1:考虑静态工厂方法而不是构造函数<强> < /p> 类允许客户端获取的实例的正常方式 其本身就是提供一个公共构造函数。还有另一种技术 这应该是每个程序员工具包的一部分。一个班级可以 提供一个公共静态工厂方法,它只是一个静态工厂 方法返回类的实例

因此,您将拥有以下界面:

public interface Foo {
     void doFoo();
}
以及实施:

public class FooImpl implements Foo {
   @Override
   public void doFoo() {
   //.. Do important code
   }
}
要使用factory方法创建类,可以使用以下方法:

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

  • 将默认构造函数设为私有,以防止类在外部实例化

    私人酒吧(){ //防止实例化 }

  • 删除构造函数中存在的重写方法的所有调用

  • 创建静态工厂方法

最后,使用工厂方法得到一个类
,如下所示:

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

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

您展示的代码在调用构造函数后调用可重写方法,而不是从构造函数调用,对吗?还是我遗漏了什么?这是关于某个特定的IDE吗?因为从编译器的角度来看,我看不出有任何错误。@user973479 afaik只有当doFoo()是Bar本身的方法时,才会出现此警告。所以您的示例或IDE是错误的。@user973479您使用的IDE是什么?IntelliJ、javac和eclipse都没有给我一个警告,很明显,
doFoo
没有理由是最终的-只有当我们调用
构造的
实例的非最终实例方法时,它才有意义。我使用SONAR进行代码覆盖,并得到了这段代码的信息。我猜SONAR中可能有一个bug?在构造函数中调用一个完全不同类的非final方法怎么可能不安全?你对我的答案投了反对票,因为你不理解构造函数中可重写行为的含义?这篇文章解释了在构造函数中调用重写方法的潜在危险:如果你真的读过我的文章,你会注意到问题是在已经完全构造的对象上调用虚拟方法。在to构造的对象上调用虚拟方法的众所周知的缺点是众所周知的,但这里不适用。我可以看到您正在使用一个具体的实现,但您的ide不能;)这就是为什么您会看到这样一条消息:如果您的IDE无法区分对本地方法的调用(只能是以下方法之一:
THIS.foo()
super.foo()
foo()
)与对实例的调用,那么您就遇到了真正的问题。同样没有,javac、intellij和eclipse都是正确的,但是OP已经指定Sonar正在发出警告-cle