Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generics wildcards and their limitations

Tags:

java

generics

I have a two part question

My book states this "If the wildcard is specified without an upper bound, then only the methods of type Object can be invoked on the values of the wildcard type"

I have no idea what this could mean. What does this mean?

Also what are the limitations place on wild card types (unbounded and bounded)? For instance if I have a reference to MyClass<?> or MyClass<? extends SomeOtherClass>, what methods am I not allowed to call through that reference. I don't understand what the wild card allows or disallows me to do, which is probably why I don't understand the quote from the book.

I have an example for the second part:

class SomeOtherClass
{
[...]
}

class MyClass<T>
{
[...]
}

class Test
{
     public static void main(String[] arg)
     {
         MyClass<? extends SomeOtherClass> myClass = new MyClass<String>() // for instance what does the wild card reference limit me to in any way. In a general sence.
     }
}
like image 695
rubixibuc Avatar asked Mar 20 '12 07:03

rubixibuc


1 Answers

Wildcards bounds (upper and lower) are often mandatory for collections and classes returning objects of parameterized type.

You'll often hear about PECS, which means "Producer extends, Consumer super". I suggest you to read the answer to this question, to avoid duplicating answers.

  • To be more precise, when you define your wildcard with <? extends TheClass>, then you're telling the compiler that the wildcarded object is at least of type TheClass. Therefore, you are able to use this object like an instance of TheClass, and call any method this type proposes.

  • Now, when you define your wildcard as <? super TheClass>, you're telling the compiler that your wildcarded object type is implemented or extended by the TheClass type. It means that the object type may not be TheClass, but that a TheClass object can be used as an instance of your wildcarded reference. Therefore, you cannot call anything on that object, since its type is only known at runtime, but you can pass the object to methods waiting for a wildcarded object.

Examples:

private void foo(List<?> list) {
    Object o = list.get(0); // ok
    list.add(new Object()); // won't compile!

    // you cannot add anything, and only extract Object instances
}

private void foo(List<? extends TheClass> list) {
    Object o1 = list.get(0);   // ok
    TheClass o2 = list.get(0); // ok
    list.add(new Object());    // won't compile!
    list.add(new TheClass());  // won't compile!

    // You are sure that the objects are of a subtype of TheClass,
    // so you can extract TheClass instances safely. However, you cannot
    // add anything to this list since its type is not known (may be
    // different from TheClass, so the compiler does not allow anything).
}

private void foo(List<? super TheClass> list) {
    Object o1 = list.get(0);   // ok
    TheClass o2 = list.get(0); // won't compile!
    list.add(new Object());    // won't compile!
    list.add(new TheClass());  // ok

    // You are sure that the objects are of a type implemented by TheClass,
    // so you can add any TheClass instances to the list. However, you cannot
    // extract TheClass objects since the objects type may be just implemented
    // by TheClass, but different.
}
like image 71
Aurelien Ribon Avatar answered Oct 19 '22 04:10

Aurelien Ribon