Java泛型SuppressWarnings(“unchecked”)神秘 [英] Java generics SuppressWarnings("unchecked") mystery

查看:146
本文介绍了Java泛型SuppressWarnings(“unchecked”)神秘的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么代码替代(1)在没有警告的情况下编译,并且代码替代(2)会产生未检查的转换警告?



>

  class Foo< T> {
Foo(T [] arg){
}
}



< (1):

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

@SuppressWarnings(unchecked)
Bar(){
super((T [])EMPTY_ARRAY);


另类(2):

  class Bar< T>延伸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 []
其中T是一个类型变量:
T extends类Bar中声明的对象
1警告

这是:

<$ p $ Java™版本1.7.0_07
Java™SE运行时环境(build 1.7.0_07-b10)
Java HotSpot™64位服务器虚拟机23.3-b01,混合模式)


解决方案

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



总之,班级成员的顺序应该完全独立于如何处理警告。这可能是未经检查的警告代码中的一个边缘案例,或者它可能是一个更大的问题。



与此同时,您可以通过做什么来消除所有问题你应该首先完成,然后动态生成空数组而不是现有的空数组,如这个问题



编辑


如果我的 EMPTY_ARRAY static final

不要再使用 static final 并在您的构造函数中提供一个 Class< T>

  @SuppressWarnings (unchecked)//仍然需要这个
public Bar(Class< T> clazz){
super((T [])Array.newInstance(clazz,0));

$ / code>

Java几乎从不使用 final的值用于警告的变量,除非是死代码。否则,你会遇到类似的情况:

  class Bar< T>延伸Foo< T> {
//真的是空的吗?
protected static final Object [] EMPTY_ARRAY = SomeOtherClass.getEmptyArray();

@SuppressWarnings(unchecked)
Bar(){
super((T [])EMPTY_ARRAY);






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



除了这个答案外,是使用var args。 Foo

  class Foo< T> {
Foo(T ... arg){
}
}

Bar :

  class Bar< T>延伸Foo< T> {

Bar(){
super();


$ / code>

这应该有效,它消除了所有的铸造,空的数组,警告等。查看更多关于var args及其可能的调用信息此处


Why does code alternative(1) compile without warnings, and code alternative(2) produce an "unchecked cast" warning?

Common for both:

class Foo<T> {
    Foo( T [] arg ) {
    }
}

Alternative (1):

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

    @SuppressWarnings("unchecked")
    Bar() {
         super( (T []) EMPTY_ARRAY );
    }
}

Alternative (2):

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

    protected static final Object [] EMPTY_ARRAY = {};
}

Alternative (2) produces:

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

This is:

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)

解决方案

I'm unable to find anything in the JLS, both the @SuppressWarnings (JLS 9.6.3.5) and unchecked warnings (JLS 5.1.9) sections don't seem to have any issues that could lead to this problem. My guess (without testing your SSCE myself) is that you've found a bug in the compiler. I'd recommend filing a bug report with Oracle and adding the report link to your question.

In short, the order of members in the class should be completely independent about how warnings are processed. It may be an edge case in just the unchecked warning code, or it may be a larger problem.

In the meantime, you can eliminate all of your problems by doing what you should have done in the first place, and dynamically generate the empty array instead of casting an existing one, as outlined in this question.

Edit

I don't see how the linked proposal would work in case of my EMPTY_ARRAY that is a static final.

Don't make it static final anymore, and provide a Class<T> in your constructor:

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

Java pretty much never uses the value of a final variable for warnings except in cases of dead code. Otherwise, you'd get edge cases like this:

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 );
    }
}

They'd have to write that logic into the compiler. It's unnecessary complication for edge cases like "empty arrays", and besides, this casting like this is all code smell in the end.

Another option you might have besides that answer is to use var args. Foo:

class Foo<T> {
    Foo( T ... arg ) {
    }
}

And Bar:

class Bar<T> extends Foo<T> {

    Bar() {
         super();
    }
}

That should work, and it eliminates all casting, empty arrays, warnings, etc. See more about var args and their possible invocations here.

这篇关于Java泛型SuppressWarnings(“unchecked”)神秘的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆