CodingKobold
CodingKobold

Reputation: 177

Why does this generic java method accept two objects of different type?

This method shall take two objects of the same type and return one of those objects by random:

public static <T> T random(T o1, T o2)
{
   return Math.random() < 0.5 ? o1 : o2;
}

Now, why does the compiler accept two parameters with distinctive types?

random("string1", new Integer(10)); // Compiles without errors

EDIT: Now that I know that both parameters are getting implicitly upcasted, I wonder why the compiler does complain when calling the following method:

public static <T> List<T> randomList(List<T> l1, List<T> l2) {
        return Math.random() < 0.5 ? l1 : l2;
    }

Call:

randomList(new ArrayList<String>(), new ArrayList<Integer>()); // Does not Compile

If those ArrayList Parameters are also getting upcasted to Object, why does it give me an error this time?

Upvotes: 8

Views: 2767

Answers (4)

newacct
newacct

Reputation: 122489

Know that I know that both parameters are getting implicitly upcasted, I wonder why the compiler does complain when calling the following method:

Because even when A is a subtype of B, List<A> is not a subtype of List<B> if A and B are different.

Upvotes: 3

irreputable
irreputable

Reputation: 45443

T is inferred to be the a common super type of String and Integer, which is

Object & Serializable & Comparable<? extends Object & Serializable & Comparable<? extends ... ...

well, nobody needs to care about that.

You can add a little more constraints on the parameter types

public static <T1,T2 extends T1> T1 random(T1 o1, T2 o2)

In your list example, you need wildcards to get the similar effect

public static <T> List<? extends T> randomList(
                                    List<? extends T> l1, List<? extends T> l2)

Upvotes: 5

NPE
NPE

Reputation: 500673

T is inferred to be Object, and both arguments are getting implicitly upcast.

Thus the code is equivalent to:

Main.<Object>random((Object)"string1", (Object)new Integer(10));

What may be even more surprising is that the following compiles:

random("string1", 10);

The second argument is getting auto-boxed into an Integer, and then both arguments are getting upcast to Object.

Upvotes: 11

JB Nizet
JB Nizet

Reputation: 691943

Because you don't call it in a safe, genericized way. Try

MyClass.<String>random("string1", new Integer(10));

And you'll get a compilation error.

Or let the compiler infer the type, and you should also get a compilation error:

String s = random("string1", new Integer(10));

Upvotes: 1

Related Questions