0

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?
SubZr0
  • 137
  • 7
  • 2
    In both cases the compiler will try to infer the type from the assignment and the parameters and in the first statement the type can correctly be inferred as `Exception` (that's the common type) while in the second inference would yield `Object` as the common case but the assignment would fail in that case. If you'd change the declaration of the second example to `ArrayList super Exception>` the assignment would work since an `ArrayList` would be allowed. – Thomas Jan 13 '17 at 12:44

3 Answers3

1

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");  
        }
}
Jekin Kalariya
  • 3,475
  • 2
  • 20
  • 32
0

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

Fabien Benoit-Koch
  • 2,784
  • 2
  • 21
  • 33
  • The inferred type is *exactly* `Exception`, as `ArrayList` would not be assignable to `ArrayList`. However, after inferring `Exception` for `T`, the parameter type of `create` is `Exception` and it is legal to pass an instance of `RuntimeException` to a method expecting an instance of `Exception`. – Holger Jan 19 '17 at 17:25
0

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");
Community
  • 1
  • 1
davidxxx
  • 125,838
  • 23
  • 214
  • 215