views:

474

answers:

3

Can someone explain to me why the following code does not work?

public class Test {

 interface Strategy<T> {
   void execute(T t);
 }

 public static class DefaultStrategy<T> implements Strategy<T> {
   @Override
   public void execute(T t) {}
 }

 public static class Client {
   private Strategy<?> a;

   public void setStrategy(Strategy<?> a) {
     this.a = a;
   }

   private void run() {
     a.execute("hello world");
   }
 }

 public static void main(String[] args) {
   Client client = new Client();
   client.setStrategy(new DefaultStrategy<String>());
   client.run();
 }
}

I'm getting the following error:

The method execute(capture#3-of ?) in the type Test.Strategy<capture#3-of ?> 
is not applicable for the arguments (String)

I've got it to work by altering code as follows:

public class Test {

 interface Strategy<T> {
  void execute(T t);
 }

 public static class DefaultStrategy<T> implements Strategy<T> {
   @Override
   public void execute(T t) {}

 }

 public static class Client<T> {
   private Strategy<T> a;

   public void setStrategy(Strategy<T> a) {
     this.a = a;
   }

   private void run(T t) {
     a.execute(t);
   }
 }

 public static void main(String[] args) {
   Client<String> client = new Client<String>();
   client.setStrategy(new DefaultStrategy<String>());
   client.run("hello world");
 }
}

but I want to understand why the original approach did not work.

A: 

That does not work because your class Client is written for no specific Strategy (Strategy<?>) but in the run() method, you pass a String (which is only correct for Strategy<String>!). That would only work if you'd change a's type and setStrategy()'s parameter to the type Strategy<String>!

Johannes Weiß
+5  A: 

The answer is simple: the unbound wildcard cannot be used. It simply means "uknown object".

It doesn't give anything informative to compiler. "?" means of whatever type, so actually it is too generic to mean anything.

Take a look here: http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html

As stated:

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error

Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.

EDIT: don't worry, this is a normal misunderstanding of java wildcard when you start using them. That's why bounded wildcards (eg. <? extends Something>) exist, otherwise generic wildcard would be almost useless since compiler cannot make any assumptions on it.

Jack
A: 

This is because this is not a type safe operation. "?" is a wildcard that means I do not know the type. It does not mean "any type". read this... http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf

Matthew Sowders