views:

92

answers:

2

If i declare a generic class as something like

public class Driver<V extends Car>

where Car is an interface.

Then, I use it with something like this:

Driver<?> driver = new Driver<Chevrolet>();

I don't want to specify a specific implementation of car as the generic.

Why is it that I cannot call methods implemented in driver that uses the generic class as the parameter?

For example if Driver has a method like

public void drive(V vehicle)

It does not allow me to call that with my instance of driver (Driver<?>).

+3  A: 

Because the compiler doesn't know what type of argument driver.drive(? vehicle) will accept. Should it take a Chevrolet, a Honda, or some other type?

For more details you might find Gilad Bracha's Generics Tutorial helpful.

What is the purpose of your drive() method. Does the vehicle parameter need to be typed to the specific subtype of Car? Would it be more appropriate for it to simply accept a Car?


The following was part of my original answer, but discussion in the comments proved that it was incorrect. I'm leaving it here so the comments aren't orphaned.

Try declaring your method like this:

public <T extends V> void drive(T vehicle)

and see if that works better for you.

ChrisH
I've fixed it in my edit.
ChrisH
I still fail to see how this answers the question. You still can't do `driver.drive(aChevrolet)`, can you?
polygenelubricants
You are right, assuming that driver is still declared as a Driver<?>, however, since class Driver requires its generics argument to be Car or a subclass of Car, it would be reasonable to declare driver as type Driver<? extends Car> without any loss of flexibility. With that additional change I think my answer works.
ChrisH
@ChrisH: No, a `Driver<? extends Car>` may be a `Driver<BMW>`, and since `Chevrolet` does not extend `BMW` (I hope I got that right, I don't know cars), you still can't `drive(aChevrolet)`.
polygenelubricants
@polygenelubricants: Yes, you are right. I'm going to edit my post again.
ChrisH
+1  A: 

The question is vague, but I believe this excerpt from Angelika Langer's Java Generics FAQ answers it:

Which methods and fields are accessible/inaccessible through a reference variable of a wildcard parameterized type?

It depends on the kind of wildcard.

Using an object through a reference variable of a wildcard parameterized type is restricted. Consider the following class:

Example (of a generic class):

class Box<T> {
  private T t;
  public Box(T t) { this.t = t; }
  public void put(T t) { this.t = t;}
  public T take() { return t; }
  public boolean equalTo(Box<T> other) {
     return this.t.equals(other.t);
  }
  public Box<T> copy() {
     return new Box<T>(t);
  }
} 

When we use a reference variable of a wildcard instantiation of type Box to access methods and fields of the referenced object the compiler would reject certain invocations.

Example (of access through a wildcard parameterized type):

class Test {
  public static void main(String[] args) {
    Box<?> box = new Box<String>("abc");

    box.put("xyz");    // error
    box.put(null);     // ok

    String s = box.take();  // error
    Object o = box.take();  // ok

    boolean equal = box.equalTo(box);            // error
    equal = box.equalTo(new Box<String>("abc")); // error

    Box<?> box1 = box.copy();       // ok
    Box<String> box2 = box.copy();  // error
  }
}

Essentially ? has less information for the generic type system, and thus to enforce typesafety certain invokations must be rejected, because they're not typesafe.

A Box<?> may be a Box<Integer>, a Box<String>, or even a Box<Box<?>>. Thus given a Box<?> box, box.put("xyz") must be rejected.

References

Related questions

polygenelubricants