为什么选中警告

问题描述:

我有几个unchecked警告,我想压制,但上来看,我仍然看到这条消息:为什么选中警告

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 

我很欣赏界面设计的建议,但我的问题是关于为什么警告没有得到suppres SED。

+4

您是否尝试使用'-Xlint:unchecked'编译?也许导致警告的代码与您压制的代码不同。 – Radiodef

+7

为什么要压制这些警告而不是修复它们?您是否在评论这些抑制因素,以及为什么他们被认为是安全的强制转换,正如在_Effective Java_一书中推荐的那样?他们实际上是否被认为是安全的演员?你的例子没有显示任何未经检查的强制转换,更不用说回答这些问题。 –

+0

我发布的代码只是一个例子。我的实际方法使用泛型并且更复杂,但这不是我的问题的主要观点。 – user2497897

你的问题实际上在于getGround()Descriptor的定义。类型变量IgetGround()的声明中是免费的,这意味着您的方法有希望返回无论什么类型的调用者选择!返回I类型值的唯一方法是以某种方式颠覆类型系统(例如通过抛出异常或返回null)。

编译器能够正确检测I呼叫者的使用getGround()可能是不同的类型中的getGround()MORBase实施J,但是编译器不能发出任何字节码检查类型(因为你'正在编译MORBase,但字节码需要插入到调用者getGround())。由于它无法检查类型,也无法插入代码来检查类型,所以它会正确地发出未经检查的警告。

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

我推荐的解决将是简单地丢弃在getGround()声明的类型变量I,并依靠亚型多态性,让你简单地声明getGround()为返回Ground<O, J>

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

如果这是不可能的,并且您需要能够返回子类型为Descriptor的子类型Ground,则需要将类型参数添加到Descriptor以确保类型被正确传播给呼叫者:

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

需要注意的是,即使指定了Descriptor接口上的getGround()方法只是返回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没有的系统或Java类型系统不支持的更高类型的约束。因此,如果您确实需要FooDescriptorFooGround之间的关系,则需要添加其他类型参数以将其关联。但是,如果你不严格需要它们之间的关系,不要通过尝试对其进行编码来使你的类型复杂化。

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

+0

当你说要修复代码时,你是否打算让开发人员不设计'Ground',它不会与特定的'Description'一起工作?这是不可能的,因为相同的泛型参数被其他方法咀嚼。我知道该参数应该传播,但认为这是一个非常简化的我的代码外推,如果我传播所有参数变得不可读。除此之外,这是外部用户永远不会看到的API中非常隐蔽的部分。 – user2497897

+0

顺便说一句,在'Description'接口中''getGround()'方法添加注释不会抑制警告。 – user2497897

+0

@ user2497897:查看我更新的答案。您可以使用并行的'FooDescriptor'和'FooGround'类,而不需要错误的类型参数。如你所示,你的Descriptor接口上的类型参数肯定是不正确的,因为它不受任何限制。 –