我想抑制一些未经检查的警告,但在运行时我仍然看到此消息:

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


我很欣赏有关界面设计的建议,但我的问题与为什么不抑制警告有关。

最佳答案

您的问题实际上出在getGround()中的Descriptor定义。在I的声明中,类型变量getGround()是自由的,这意味着您的方法有望返回调用者选择的任何类型!返回I类型的值的唯一方法是通过某种方式破坏类型系统(例如,引发异常或返回null)。

编译器正确检测到调用方使用I时的getGround()可能与JgetGround()的实现中的MORBase类型不同,但是编译器无法发出任何字节码来检查类型(因为您正在编译MORBase,但是字节码将需要插入到getGround()的调用程序中)。由于它无法检查类型,并且无法插入代码来检查类型,因此它正确地发出了未经检查的警告。

通过将@SuppressWarnings批注附加到getGround()接口中的Descriptor声明中,可能实际上可以消除此警告,但是您实际上不应该这样做。相反,请修复您的代码。

我建议的解决方法是将类型变量I放在getGround()的声明中,然后依靠子类型的多态性使您可以简单地将getGround()声明为返回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()接口上的Descriptor方法指定为仅返回Ground<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() {
        ...
    }
}


仅当您要强制FooDescriptorFooGround之间建立某种关系时,才会出现此问题。这将需要Java不具备的traits系统或Java类型系统不支持的更高类型的类型约束。因此,如果您确实需要FooDescriptorFooGround之间的关系,则需要添加另一个类型参数来将它们关联。但是,如果您严格不需要它们之间的关系,则不要通过尝试编码来使类型复杂化。

请注意,此问题通常称为“并行继承层次结构”问题,并且在SoftwareEngineering.SE上有很多关于此问题,例如this one

07-23 20:09