简体   繁体   中英

Why does compiler behave like this?

Look, we've got come code:

public class Test2 {
    public static void main(String... args) {
        ArrayList<Exception> a = new ArrayListFactory().create(new RuntimeException());
        ArrayList<Exception> b = new ArrayListFactory().create("Z");
        }
}

class ArrayListFactory {
    public <T> ArrayList<T> create(T example) {
        return new ArrayList<T>(10);
    }
}

and an compilation error on second statement:

Error:(15, 63) java: incompatible types: inference variable T has incompatible bounds
    equality constraints: java.lang.Exception
    lower bounds: java.lang.String
  1. In fact, the first statement assigns to ArrayList<Exception> another ArrayList<RuntimeException> , doesnt it clash with java rules?
  2. The second statement infers Exception type argument for create . Does it check that method's return type matches it's argument type as it's defined in ArrayListFactory class? It seems that this method call shall be resolved dynamically, why is compiler sure that it's processing the correct method?

All Generic type will assign at compile time so compiler will infer type from your assignment and its expected both to be same, but in your case its different, so it will give type mismatch error, change code like this to fix the errors.

public class Test2 {

    public static void main(String... args) {
        ArrayList<RuntimeException> a = new ArrayListFactory().create(new RuntimeException());
        ArrayList<String> b = new ArrayListFactory().create("Z");  
        }
}

In this statement:

ArrayList<Exception> b = new ArrayListFactory().create("Z");

The compiler uses type inference (from the declaration ArrayList<Exception> ) to add a constraint on the generic return type of create() . It's called a Target Type . The target type of an expression is the data type that the Java compiler expects depending on where the expression appears.

In this case, T should be a subclass of Exception. RuntimeException is thus fine; but String is not.

This feature appeared with Java 8. More information on it : http://docs.oracle.com/javase/8/docs/technotes/guides/language/enhancements.html

1) First call

    ArrayList<Exception> a = new ArrayList<RuntimeException>();

is not a legal use of Generics in Java. You can go to Explanation of the get-put principle to understand.

2) Second call

The inference of the T Type depends on the returned type declared from the caller.

Here the caller declares the returned type as Exception :

 ArrayList<Exception> b = new ArrayListFactory().create("Z");

Whereas the compilation error :

Error:(15, 63) java: incompatible types: inference variable T has incompatible

bounds equality constraints: java.lang.Exception

To pass a String :

 ArrayList<String> b = new ArrayListFactory().create("Z");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM