Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generics: How does method inference work when wildcard is being used in the method parameters?

Tags:

java

generics

Supposedy i have the following:

class x {

public static void main(String [] args) {
    List <?> a = new LinkedList<Object>();
    List <? extends Object> b = new LinkedList<Object>();
    List <? super Object> c = new LinkedList<Object>();
    abc(a, "Hello"); // (1) Error
    abc(b, "Hello"); // (2) Error
    abc(c, "Hello"); // (3) ok  
    def(b); // (4) ok

// Showing inference at work
    Integer[] a = {10, 20, 30};  // (5)
    T is inferred to be ? extends Object
    Method signature: ppp(? extends Object, ? extends Object[])
    Method call signature: ppp(String, Integer[]);
    ppp("Hello", a); // ok

}

static <T> void abc(List<T> a, T b) {}  
static <T> void def(List<T> a) {}
static <T> void ppp(T t1, T[] t2){}

}  

To begin with, look at clause 5 showing inference at work. Now clause 5 section is a working section.

If that is what it is, then why does clause (1) & (2) have errors?

From my view, all these 3 methods calling have the same inference generated since no actual type parameters is used on the abc method call.

method parameter <T> abc (List <T> a, T b>)
inferred <Object> abc (List <Object>, Object) // (4)

Please bear in mind, method abc() and def() is my method. Compiler doesn't know what i want to do with the List in this method. I might just print the list size or might not even do anything at all as shown above. So there is no get or set involved here.

CONTINUATION --> This is getting very confusing for me.

class y {

public static void main(String [] args) {
    List <Integer> a = new LinkedList<Integer>();
    List <Object> b = new LinkedList<Object>();
    ppp("Hello", new Integer(1)); // (20) ok
    qqq("Hello", a); // (21) error
    qqq("Hello", b); // (22) ok
}

static <T> void ppp(T t1, T t2) {}
static <T> void qqq(T t1, List <T> t2) {}
}

Note that clause 21 is the same as clause 20 except 2nd parameter is being made to be a List instead of Integer.

Clause 20 is ok cos' T is inferred to be Object.
Clause 22 is ok. Same reason as clause 20.
Clause 21 failed? T could also be inferred to be Object too - would work too?

like image 209
yapkm01 Avatar asked Sep 26 '11 15:09

yapkm01


People also ask

When using generics in Java When will you use a wild card and when will you mot use a wild card?

We can use the Java Wildcard as a local variable, parameter, field or as a return type. But, when the generic class is instantiated or when a generic method is called, we can't use wildcards. The wildcard is useful to remove the incompatibility between different instantiations of a generic type.

What is the use of wildcard in generics?

In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific).

What is wild card in generics in Java?

The question mark (?) is known as the wildcard in generic programming. It represents an unknown type. The wildcard can be used in a variety of situations such as the type of a parameter, field, or local variable; sometimes as a return type.

How does type inference work in Java?

Type inference represents the Java compiler's ability to look at a method invocation and its corresponding declaration to check and determine the type argument(s). The inference algorithm checks the types of the arguments and, if available, assigned type is returned.


1 Answers

The hard thing about the wildcard is to realize ? extends Foo does not mean "anything that extends Foo", but instead it means "some specific type that extends Foo". And since you are outside that definition, you have no way to know which specific sub-type of Foo it is.

Update:

As I said, it's complicated. Here are some comments on your code.

// a list of some specific type, and you don't know what type that is.
// it's a sub-type ob Object, yes, which means that you can do
// Object foo = a.get(0); , but the compiler has no way of knowing
// whether it's a String so you can't pass in a String
List <?> a = new LinkedList<Object>();
// same here. '?' and '? extends Object' are equivalent
List <? extends Object> b = new LinkedList<Object>();
// this is a list of Objects and superclasses thereof.
// since there are no superclasses of Object, this is equivalent to
// List<Object>. And through inheritance, a String is an Object, so
// you can pass it in.
List <? super Object> c = new LinkedList<Object>();

Update 2:

The problem here is that you are dealing with fixed, but unresolveable variables.

// you can pass in a List<String> and  a String,
// but if you pass in a List<?>, the compiler has no idea what
// '?' is and just can't substitute 'String'.
// 'T' doesn't help you here, because 'T' can't match both
// '?' and 'String'.
static <T> void abc(List<T> a, T b) {}  
// this works because 'T' substitutes '?' and doesn't have to worry
// about a 2nd parameter
static <T> void def(List<T> a) {}

Read this question, it might shed some light on the problem:

What is PECS (Producer Extends Consumer Super)?

like image 131
Sean Patrick Floyd Avatar answered Nov 12 '22 14:11

Sean Patrick Floyd