2009-11-05 4 views
6

Может кто-нибудь объяснить мне, почему следующий код не работает?generics error: неприменимо для аргументов

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(); 
} 
} 

Я получаю следующее сообщение об ошибке:

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

Я получил его на работу, изменяя код следующим образом:

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"); 
} 
} 

, но я хочу, чтобы понять, почему оригинал подход не работает.

ответ

0

Это не работает, потому что ваш класс Client написана для каких-либо конкретных Strategy (Strategy<?>), но в методе run(), вы передаете String (который является правильным только для Strategy<String>!). Это будет работать, только если вы измените тип a и параметр setStrategy() на тип Strategy<String>!

11

Ответ прост: несвязанный шаблон нельзя использовать. Это просто означает «укененный объект».

Это не дает ничего информативного компилятору. "?" средства любого типа, так что на самом деле это слишком общее, чтобы означать что угодно.

Посмотрите здесь: http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html

Как сказано:

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

Поскольку мы не знаем, что тип элемента с означает, что мы не можем добавлять объекты к нему. Метод add() принимает аргументы типа E, тип элемента коллекции. Когда фактический параметр типа есть?, Это означает какой-то неизвестный тип. Любой параметр, который мы передаем для добавления, должен быть подтипом этого неизвестного типа. Поскольку мы не знаем, что это такое, мы ничего не можем передать. Единственным исключением является null, который является членом каждого типа.

EDIT: не беспокойтесь, это обычное недоразумение подстановки java, когда вы начнете их использовать. Вот почему существуют ограниченные подстановочные знаки (например, <? extends Something>), в противном случае общий шаблон будет почти бесполезен, поскольку компилятор не может делать никаких предположений.

0

Это потому, что это не безопасная операция типа. "?" это подстановочный знак, который означает, что я не знаю тип. Это не означает «любой тип». читать далее ... http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf