我想抑制一些未经检查的警告,但在运行时我仍然看到此消息:
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()
可能与J
中getGround()
的实现中的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() {
...
}
}
仅当您要强制
FooDescriptor
和FooGround
之间建立某种关系时,才会出现此问题。这将需要Java不具备的traits系统或Java类型系统不支持的更高类型的类型约束。因此,如果您确实需要FooDescriptor
和FooGround
之间的关系,则需要添加另一个类型参数来将它们关联。但是,如果您严格不需要它们之间的关系,则不要通过尝试编码来使类型复杂化。请注意,此问题通常称为“并行继承层次结构”问题,并且在SoftwareEngineering.SE上有很多关于此问题,例如this one。