Java generics SuppressWarnings(“unchecked”) mystery

前端 未结 4 1397
盖世英雄少女心
盖世英雄少女心 2021-02-14 03:28

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

Common for both:

class Foo         


        
4条回答
  •  囚心锁ツ
    2021-02-14 03:47

    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 in your constructor:

    @SuppressWarnings("unchecked") // Still need this
    public Bar(Class 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 extends Foo {
        // 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 {
        Foo( T ... arg ) {
        }
    }
    

    And Bar:

    class Bar extends Foo {
    
        Bar() {
             super();
        }
    }
    

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

提交回复
热议问题