Java泛型SuppressWarnings("未选中")之谜

Joh*_*nst 11 java generics unchecked suppress-warnings java-7

为什么代码替代(1)编译时没有警告,代码替代(2)产生"未经检查的强制转换"警告?

两者共同:

class Foo<T> {
    Foo( T [] arg ) {
    }
}
Run Code Online (Sandbox Code Playgroud)

替代方案(1):

class Bar<T> extends Foo<T> {
    protected static final Object [] EMPTY_ARRAY = {};

    @SuppressWarnings("unchecked")
    Bar() {
         super( (T []) EMPTY_ARRAY );
    }
}
Run Code Online (Sandbox Code Playgroud)

替代方案(2):

class Bar<T> extends Foo<T> {
    @SuppressWarnings("unchecked")
    Bar() {
         super( (T []) EMPTY_ARRAY );
    }

    protected static final Object [] EMPTY_ARRAY = {};
}
Run Code Online (Sandbox Code Playgroud)

备选方案(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
Run Code Online (Sandbox Code Playgroud)

这是:

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)
Run Code Online (Sandbox Code Playgroud)

Bri*_*ian 4

我无法在 JLS 中找到任何内容,@SuppressWarningsJLS 9.6.3.5)和未经检查的警告(JLS 5.1.9)部分似乎没有任何可能导致此问题的问题。我的猜测(没有亲自测试您的 SSCE)是您在编译器中发现了一个错误。我建议向 Oracle 提交错误报告并将报告链接添加到您的问题中。

简而言之,类中成员的顺序应该完全独立于警告的处理方式。这可能只是未经检查的警告代码中的边缘情况,也可能是一个更大的问题。

同时,您可以通过执行您应该首先执行的操作来消除所有问题,并动态生成空数组而不是转换现有数组,如本问题中所述。

编辑

我不知道如果我的提案EMPTY_ARRAYstatic final.

不要static final再这样做了,并Class<T>在构造函数中提供:

@SuppressWarnings("unchecked") // Still need this
public Bar(Class<T> clazz) {
    super((T[]) Array.newInstance(clazz, 0));
}
Run Code Online (Sandbox Code Playgroud)

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 );
    }
}
Run Code Online (Sandbox Code Playgroud)

他们必须将该逻辑写入编译器。对于像“空数组”这样的边缘情况来说,这是不必要的复杂化,而且,像这样的转换最终都是代码味道。

除了这个答案之外,您可能还有的另一个选择是使用 var args。Foo:

class Foo<T> {
    Foo( T ... arg ) {
    }
}
Run Code Online (Sandbox Code Playgroud)

Bar

class Bar<T> extends Foo<T> {

    Bar() {
         super();
    }
}
Run Code Online (Sandbox Code Playgroud)

这应该可行,并且它消除了所有强制转换、空数组、警告等。请在此处查看有关 var args 及其可能调用的更多信息。