Marcus Junius Brutus
Marcus Junius Brutus

Reputation: 27306

why does this compile without any unchecked type warnings?

Why does the following code compile cleanly without any warnings, even with xlint:all ?

class A<V> {

    public V v;

    public <V> A() {
    }

    public static <V> A<V> create() {
        return new A<V>();
    }
}


public class FooMain {

    public static void main(String args[]) {
        A.create().v = 5;
        A.create().v = "a string";
    }
}

running:

javac -Xlint:all src/FooMain.java

results in a clean compile without any warnings (unchecked, etc.). What is the type parametrization of the instance of the generic class A that gets's created on the first line and what on the second? And how does the compiler determine the type? By looking at the type of the r-values?

Upvotes: 9

Views: 152

Answers (2)

Paul Bellora
Paul Bellora

Reputation: 55233

In both of the statements, the compiler does not have enough information to infer the type argument for V. When this happens, it defaults to V's upper bound, which is Object.

The assignments are valid because both 5 and "a string" are assignable to Object.

We can show that the type of A.create().v is Object by trying to assign it to a more specific type:

Integer i = A.create().v; // Type mismatch: cannot convert from Object to Integer

The error is the same, even if we assign a more specific type first (the result of an assignment expression is the type of the assigned variable):

Integer i = (A.create().v = 5); // same error

Note that a "type witness" can be used to explicitly specify generic type arguments, in the case that they aren't inferred:

Integer i = A.<Integer>create().v; // valid

A.<String>create().v = 5;           // incompatible types
A.<Integer>create().v = "a string"; //

These are contrived examples just to demonstrate compiler behavior, but a type witness is occasionally useful, for example:

static void m(List<String> list) { }

public static void main(String args[]) {

    m(Collections.emptyList());         // error
    m(Collections.<String>emptyList()); // valid
}

Upvotes: 4

Girish
Girish

Reputation: 1717

Due to these two statement

A.create().v = 5;
A.create().v = "a string";

Compiler will easily resolve in the first case <V> by <Integer>

and in the second case <V> by <String>

Upvotes: 1

Related Questions