为什么未经检查的警告不会被抑制

时间:2017-05-30 21:41:43

标签: java intellij-idea suppress-warnings

我有几个未经检查的警告,我想抑制但在运行中我仍然看到这条消息:

Note: Some input files use unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

我使用以下类型的注释,实际上警告消息在IDE源代码中消失。

@Override @SuppressWarnings("unchecked") 
public GroundBase<J> getGround() {
    return ground;
}

我将我的代码作为公共API分发,我想知道用户在使用过程中是否会看到该消息。

我正在使用 junit 测试我的代码。 我使用的是Java 8和intelliJ 2016.3.6。

我查看了-Xlint:unchecked建议详细信息。代码中没有更多未注释的部分,但编译器建议仍然不会消失(或减少)。

修改

更好地将我得到的警告之一进行了语境化,这里是一个简化但仍然相关的代码部分:

abstract public class MORBase<J extends OWLObject>
    implements Descriptor<OWLReferences,J>, MORGround<J>

    @Override @SuppressWarnings("unchecked")
    public GroundBase<J> getGround() {
        return ground;
    }
}

interface Ground<O,J>{
    Ground<J> getGround();
}

interface Descriptor<O,J> {
    <I extends Ground<O,J>> I getGround();
}

这里有关于它的完整信息:

warning: [unchecked] getGround() in MORBase implements <I>getGround() in Descriptor
public GroundBase<J> getGround() {
                     ^
return type requires unchecked conversion from GroundBase<J#1> to I
where J#1,I,O,J#2 are type-variables:
    J#1 extends OWLObject declared in class MORBase
    I extends Ground<O,J#2> declared in method <I>getGround()
    O extends Object declared in interface Descriptor
    J#2 extends Object declared in interface Descriptor

我很欣赏有关界面设计的建议,但我的问题与警告未被抑制的原因有关。

1 个答案:

答案 0 :(得分:1)

您的问题实际上取决于getGround()Descriptor的定义。类型变量IgetGround()的声明中是免费的,这意味着您的方法承诺返回 调用者选择的任何类型!返回类型I的唯一方法是以某种方式破坏类型系统(例如,通过抛出异常或返回null)。

编译器正确检测到I来电者使用getGround()的{​​{1}}可能与J的实施中的getGround()不同在MORBase中,但编译器无法发出任何字节码来检查类型(因为您正在编译MORBase,但字节码需要插入调用者 getGround())。由于它无法检查类型,并且无法插入代码来检查类型,因此它会正确地发出未经检查的警告。

可以通过将@SuppressWarnings注释附加到getGround()界面中的Descriptor声明来实际抑制此警告,但实际上您不应该这样做。相反,修复你的代码。

我建议的解决方法是简单地在I的声明中删除类型变量getGround(),并依靠子类型多态来允许您简单地将getGround()声明为返回{{1 }}:

Ground<O, J>

如果这不可能,并且您需要能够以interface Descriptor<O,J> { Ground<O,J> getGround(); } 的子类型返回Ground的子类型,则需要向Descriptor添加类型参数以确保类型正确传播到调用者:

Descriptor

请注意,即使指定interface Descriptor<O, J, G extends Ground<O, J>> { G getGround(); } 接口上的getGround()方法只返回DescriptorGround<O, J>的子类型仍然可以将方法专门化为返回更具体的子类型。例如,这是完全合法的(并且是安全的):

Descriptor

如果您想强制执行interface Descriptor<O, J> { Ground<O, J> getGround(); } public final class FooDescriptor<O, J> implements Descriptor<O, J> { @Override public FooGround<O, J> getGround() { ... } } FooDescriptor之间的某种关系,则只会出现此问题。这需要一个Java没有的 traits 系统,或者Java类型系统不支持的更高级的类型约束。因此,如果您确实需要FooGroundFooDescriptor之间的关系,则需要添加另一个类型参数来关联它们。但是如果你不严格需要它们之间的关系,不要通过尝试对其进行编码来使你的类型复杂化。

请注意,此问题通常称为“并行继承层次结构”问题,并且在SoftwareEngineering.SE上存在大量关于它的问题,如this one