为什么未经检查的警告不会被抑制
Why unchecked warning would not be suppressed
我有几个未经检查的警告,我想禁止显示,但在 运行 我仍然看到这条消息:
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;
}
我将我的代码作为 public 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
我很欣赏关于界面设计的建议,但我的问题是关于为什么警告没有被抑制。
你的问题其实出在Descriptor
中getGround()
的定义上。类型变量 I
在 getGround()
的声明中是自由的,这意味着您的方法承诺 return 调用者 的任何类型]选择! return 类型 I
的值的唯一方法是以某种方式颠覆类型系统(例如,通过抛出异常或 returning null
)。
编译器正确检测到 调用者 中的 I
对 getGround()
的使用可能与 J
在实现中的类型不同MORBase
中的 getGround()
,但编译器无法发出任何字节码来检查类型(因为您正在编译 MORBase
,但需要将字节码插入 来电者 getGround()
)。由于它无法检查类型,也无法插入代码来检查类型,因此它会正确发出未经检查的警告。
通过将 @SuppressWarnings
注释附加到 Descriptor
接口中 getGround()
的声明中,实际上可能会抑制此警告,但您确实不应该这样做。相反,请修复您的代码。
我推荐的修复方法是简单地在 getGround()
的声明中删除类型变量 I
,并依靠子类型多态性来允许您简单地将 getGround()
声明为 returning Ground<O, J>
:
interface Descriptor<O,J> {
Ground<O,J> getGround();
}
如果那是不可能的,并且你需要能够在Descriptor
的子类型中return Ground
的子类型,那么你需要向[=14]添加一个类型参数=] 以确保类型正确传播给调用者:
interface Descriptor<O, J, G extends Ground<O, J>> {
G getGround();
}
请注意,即使 Descriptor
接口上的 getGround()
方法仅指定为 return Ground<O, J>
,[=14= 的子类型仍然可能] 将方法专门化为 return 更具体的子类型。例如,这是完全合法(且安全)的:
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
之间强制执行某种关系时才会出现问题。这将需要 traits 系统,Java 没有,或者更高种类的类型约束,Java 的类型系统不支持.所以如果你真的需要 FooDescriptor
和 FooGround
之间的关系,你需要添加另一个类型参数来关联它们。但是,如果您并不严格需要它们之间的关系,请不要通过尝试对一个进行编码来使您的类型复杂化。
请注意,此问题通常称为 "parallel inheritance hierarchy" 问题,并且在 SoftwareEngineering.SE 上有很多关于它的现有问题,例如 this one。
我有几个未经检查的警告,我想禁止显示,但在 运行 我仍然看到这条消息:
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;
}
我将我的代码作为 public 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
我很欣赏关于界面设计的建议,但我的问题是关于为什么警告没有被抑制。
你的问题其实出在Descriptor
中getGround()
的定义上。类型变量 I
在 getGround()
的声明中是自由的,这意味着您的方法承诺 return 调用者 的任何类型]选择! return 类型 I
的值的唯一方法是以某种方式颠覆类型系统(例如,通过抛出异常或 returning null
)。
编译器正确检测到 调用者 中的 I
对 getGround()
的使用可能与 J
在实现中的类型不同MORBase
中的 getGround()
,但编译器无法发出任何字节码来检查类型(因为您正在编译 MORBase
,但需要将字节码插入 来电者 getGround()
)。由于它无法检查类型,也无法插入代码来检查类型,因此它会正确发出未经检查的警告。
通过将 @SuppressWarnings
注释附加到 Descriptor
接口中 getGround()
的声明中,实际上可能会抑制此警告,但您确实不应该这样做。相反,请修复您的代码。
我推荐的修复方法是简单地在 getGround()
的声明中删除类型变量 I
,并依靠子类型多态性来允许您简单地将 getGround()
声明为 returning Ground<O, J>
:
interface Descriptor<O,J> {
Ground<O,J> getGround();
}
如果那是不可能的,并且你需要能够在Descriptor
的子类型中return Ground
的子类型,那么你需要向[=14]添加一个类型参数=] 以确保类型正确传播给调用者:
interface Descriptor<O, J, G extends Ground<O, J>> {
G getGround();
}
请注意,即使 Descriptor
接口上的 getGround()
方法仅指定为 return Ground<O, J>
,[=14= 的子类型仍然可能] 将方法专门化为 return 更具体的子类型。例如,这是完全合法(且安全)的:
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
之间强制执行某种关系时才会出现问题。这将需要 traits 系统,Java 没有,或者更高种类的类型约束,Java 的类型系统不支持.所以如果你真的需要 FooDescriptor
和 FooGround
之间的关系,你需要添加另一个类型参数来关联它们。但是,如果您并不严格需要它们之间的关系,请不要通过尝试对一个进行编码来使您的类型复杂化。
请注意,此问题通常称为 "parallel inheritance hierarchy" 问题,并且在 SoftwareEngineering.SE 上有很多关于它的现有问题,例如 this one。