为什么选择代码(1)编译时没有警告,而选择代码(2)产生“未经检查的转换”警告?
两者共有:
class Foo<T> {
Foo( T [] arg ) {
}
}
备选方案(1):
class Bar<T> extends Foo<T> {
protected static final Object [] EMPTY_ARRAY = {};
@SuppressWarnings("unchecked")
Bar() {
super( (T []) EMPTY_ARRAY );
}
}
备选方案(2):
class Bar<T> extends Foo<T> {
@SuppressWarnings("unchecked")
Bar() {
super( (T []) EMPTY_ARRAY );
}
protected static final Object [] EMPTY_ARRAY = {};
}
备选方案(2)产生:
javac -Xlint:unchecked Foo.java Bar.java
Bar.java:4: warning: [unchecked] unchecked cast
super( (T []) EMPTY_ARRAY );
^
required: T[]
found: Object[]
where T is a type-variable:
T extends Object declared in class Bar
1 warning
这是:
java version "1.7.0_07"
Java(TM) SE Runtime Environment (build 1.7.0_07-b10)
Java HotSpot(TM) 64-Bit Server VM (build 23.3-b01, mixed mode)
最佳答案
我无法在JLS中找到任何内容,@SuppressWarnings
(JLS 9.6.3.5)和未经检查的警告(JLS 5.1.9)部分似乎都没有可能导致此问题的问题。我的猜测(没有亲自测试您的SSCE)是您在编译器中发现了一个错误。我建议filing a bug report with Oracle并将报告链接添加到您的问题。
简而言之,类中成员的顺序应完全独立于警告的处理方式。仅在未经检查的警告代码中,这可能是一个极端情况,或者可能是一个更大的问题。
同时,您可以通过首先完成应做的事情来消除所有问题,并动态生成空数组,而不是像this question中所概述的那样强制转换现有数组。
编辑
不再使用static final
,并在构造函数中提供Class<T>
:
@SuppressWarnings("unchecked") // Still need this
public Bar(Class<T> clazz) {
super((T[]) Array.newInstance(clazz, 0));
}
Java几乎从不使用
final
变量的值来进行警告,除非出现死代码。否则,您将获得如下所示的极端情况:class Bar<T> extends Foo<T> {
// Is it really empty?
protected static final Object [] EMPTY_ARRAY = SomeOtherClass.getEmptyArray();
@SuppressWarnings("unchecked")
Bar() {
super( (T []) EMPTY_ARRAY );
}
}
他们必须将该逻辑写入编译器。对于像“空数组”这样的边缘情况,这是不必要的复杂化,此外,像这样的转换最终都是代码的味道。
除了该答案之外,您可能还有的另一种选择是使用var args。
Foo
:class Foo<T> {
Foo( T ... arg ) {
}
}
和
Bar
:class Bar<T> extends Foo<T> {
Bar() {
super();
}
}
这应该起作用,并且消除所有强制转换,空数组,警告等。有关var args及其可能的调用here的更多信息,请参见。