在构造函数中调用可覆盖的方法,即使我们从超类中指定了它?

时间:2015-06-25 17:44:57

标签: java constructor polymorphism

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

考虑下面的例子:

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

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

在这里,我调用registerModule,这是一个来自超类的可覆盖方法。但是,我清楚地表明我想从超类中调用该方法,而不是任何其他类,但我仍然有警告声明我不应该从构造函数中调用可覆盖的方法。我从SonarQube那里得到了警告(鱿鱼:S1699,确切地说),我正在为我的代码进行静态分析。

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

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

的类

1 个答案:

答案 0 :(得分:1)

你的代码是“安全的”,因为如果类超越方法,那么总是会调用super - 也许SonarQube过于谨慎。

但是,可覆盖或不覆盖,this已经转义了构造函数 - 正在初始化的实例可以从registerModule()传递到另一个处于不完全/不一致初始化状态的进程 - 所以无论如何都是不好的做法。即使该方法的当前实现可能将其传递出去,未来也可能(即升级库可能会引入错误)。

要解决此问题,您可以使用//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();是多余的;可以在不改变行为的情况下删除它。