类型注释属于有界通配符的什么位置?
Where does the Type Annotation belong in a bounded wildcard?
我最近开始使用 Eclipse 的 nullability 注释更新我的 Java 项目。我有一个 JavaFX 基础项目,包含一些翻译 类.
现在,在我的 LocalizedList 中,我用文档树中的一个元素对其进行初始化,然后递归地添加其所有子元素。
@NonNullByDefault
private void locChildren(Styleable c) {
String localizable = getKey(c);
if(localizable != null) {
backingMap.put(c, localizable);
setText(c, localizable);
}
if(c instanceof MenuBar) {
MenuBar mb = (MenuBar)c;
initLoc(mb.getMenus());
} // else if ...
}
@NonNullByDefault
public void initLoc(List<? extends Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
现在,如果我只保留它,我会收到非常长的警告消息
Null type safety (type annotations): The expression of type 'ObservableList<Menu>' needs unchecked conversion to conform to '@NonNull List<? extends @NonNull Styleable>', corresponding supertype is 'List<Menu>'
这是因为 MenuBar#getMenus() 没有使用任何 可空性 注释进行注释,这是意料之中的。
将@Nullable 注解应用到列表本身后,问题并没有解决。因此,我将 @Nullable 添加到通配符中。这是我偶然发现一些令人困惑的地方。
@NonNullByDefault
public void initLoc1(@Nullable List<@Nullable ? extends Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
@NonNullByDefault
public void initLoc2(@Nullable List<@Nullable ? extends @Nullable Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
@NonNullByDefault
public void initLoc3(@Nullable List<? extends @Nullable Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
这三个声明中的每一个都是有效的并且可以正常编译,但是只有最后一个声明使警告消息消失。
我原以为第一个是有效的,因为它实际上注释了方法本身中使用的 "type",并且完全被第二个示例搞糊涂了。
这三个声明之间的语义区别究竟是什么,为什么三个有效,而两个和一个无效?
要理解原始代码示例,有必要了解 @NonNullByDefault, which can be fine tuned using enum DefaultLocation 的确切效果。后者提到
Wildcards and the use of type variables are always excluded from NonNullByDefault.
另一方面,通配符绑定 extends Styleable
是 受 @NonNullByDefault
.
影响
这解释了为什么 initLoc
的预期参数类型是 @NonNull List<? extends @NonNull Styleable>
。方法 initLoc3
解决了编译错误,因为它完全覆盖了这两个 @NonNull
注释,如此处所示 - 通过在这些位置显式声明 @Nullable
。
至于将显式 @Nullable
应用于通配符本身,Eclipse 遵循为 Checkers Framework 提出的 concepts。特别是 @Nullable ?
被解释为具有可空 属性.
的下限和上限
这解释了为什么 initLoc2
与 initLoc3
不同:它定义了一个额外的 lower 边界,然后与实际参数不匹配。
为了解决关于 MenuBar
的问题,您可能需要考虑使用 external annotations.
免责声明:我无法准确重现您的情况,因为我缺少所示方法的 class 上下文。 getKey
、backingMap
和 setText
是从哪里来的?
我最近开始使用 Eclipse 的 nullability 注释更新我的 Java 项目。我有一个 JavaFX 基础项目,包含一些翻译 类.
现在,在我的 LocalizedList 中,我用文档树中的一个元素对其进行初始化,然后递归地添加其所有子元素。
@NonNullByDefault
private void locChildren(Styleable c) {
String localizable = getKey(c);
if(localizable != null) {
backingMap.put(c, localizable);
setText(c, localizable);
}
if(c instanceof MenuBar) {
MenuBar mb = (MenuBar)c;
initLoc(mb.getMenus());
} // else if ...
}
@NonNullByDefault
public void initLoc(List<? extends Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
现在,如果我只保留它,我会收到非常长的警告消息
Null type safety (type annotations): The expression of type 'ObservableList<Menu>' needs unchecked conversion to conform to '@NonNull List<? extends @NonNull Styleable>', corresponding supertype is 'List<Menu>'
这是因为 MenuBar#getMenus() 没有使用任何 可空性 注释进行注释,这是意料之中的。
将@Nullable 注解应用到列表本身后,问题并没有解决。因此,我将 @Nullable 添加到通配符中。这是我偶然发现一些令人困惑的地方。
@NonNullByDefault
public void initLoc1(@Nullable List<@Nullable ? extends Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
@NonNullByDefault
public void initLoc2(@Nullable List<@Nullable ? extends @Nullable Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
@NonNullByDefault
public void initLoc3(@Nullable List<? extends @Nullable Styleable> s) {
for(Styleable c : s) {
locChildren(c);
}
}
这三个声明中的每一个都是有效的并且可以正常编译,但是只有最后一个声明使警告消息消失。
我原以为第一个是有效的,因为它实际上注释了方法本身中使用的 "type",并且完全被第二个示例搞糊涂了。
这三个声明之间的语义区别究竟是什么,为什么三个有效,而两个和一个无效?
要理解原始代码示例,有必要了解 @NonNullByDefault, which can be fine tuned using enum DefaultLocation 的确切效果。后者提到
Wildcards and the use of type variables are always excluded from NonNullByDefault.
另一方面,通配符绑定 extends Styleable
是 受 @NonNullByDefault
.
这解释了为什么 initLoc
的预期参数类型是 @NonNull List<? extends @NonNull Styleable>
。方法 initLoc3
解决了编译错误,因为它完全覆盖了这两个 @NonNull
注释,如此处所示 - 通过在这些位置显式声明 @Nullable
。
至于将显式 @Nullable
应用于通配符本身,Eclipse 遵循为 Checkers Framework 提出的 concepts。特别是 @Nullable ?
被解释为具有可空 属性.
这解释了为什么 initLoc2
与 initLoc3
不同:它定义了一个额外的 lower 边界,然后与实际参数不匹配。
为了解决关于 MenuBar
的问题,您可能需要考虑使用 external annotations.
免责声明:我无法准确重现您的情况,因为我缺少所示方法的 class 上下文。 getKey
、backingMap
和 setText
是从哪里来的?