在构造函数中调用可重写的方法,即使我们指定它来自超级 class?

Calling a overridable method in a constructor, even if we specify it's from the super class?

我理解为什么在构造函数中调用可重写方法是一种不好的做法并且会导致错误。但是,我尝试使用前缀 super 调用可覆盖方法,以指定我想从 super class 而不是任何其他 classes.

调用该方法

考虑我下面的例子:

public class ObjectMapperExtended extends ObjectMapper {
    // fields and stuff, irrelevant to the problem

    public ObjectMapperExtended () {
        super();
        super.registerModule(new Hibernate4Module());
    }
}

在这里,我调用了 registerModule,它是 super class 的一个可覆盖方法。但是,我明确表示我想从超级 class 调用该方法,而不是任何其他 classes,但我仍然收到警告,指出我不应该从构造函数。我从 SonarQube(准确地说是 squid:S1699)收到警告,我 运行 用于对我的代码进行静态分析。

我是不是误会了什么?在这种特殊情况下指定 super 没有任何区别吗?

PS: 使用的 ObjectMapper class 来自 http://fasterxml.github.io/jackson-databind/javadoc/2.3.0/com/fasterxml/jackson/databind/ObjectMapper.html

您的代码是 "safe",因为如果 class 覆盖了该方法,将始终调用 super 的代码 - 也许 SonarQube 过于谨慎了。

然而,无论是否可覆盖,this 已经逃脱了构造函数 - 正在初始化的实例可以从 registerModule() 传递到处于 incompletely/inconsistently 初始化状态的另一个进程 - 所以它是无论哪种方式都是不好的做法。即使该方法的 当前 实现可能 不会 传递出去,未来的一个可能(即升级库可能引入错误)。

要解决此问题,您可以用 //NOSONAR 标记有问题的行以明确忽略(所有)警告:

public class ObjectMapperExtended extends ObjectMapper {
    public ObjectMapperExtended () {
        super.registerModule(new Hibernate4Module()); //NOSONAR
    }
}

或(最佳实践)使用工厂方法:

public class ObjectMapperExtended extends ObjectMapper {
    private ObjectMapperExtended () {}

    public static ObjectMapperExtended create() {
        ObjectMapperExtended obj = new ObjectMapperExtended();
        obj.registerModule(new Hibernate4Module());
        return obj;
    }
}

顺便说一句,调用super();是多余的;它可以在不改变行为的情况下被删除。