2009-11-05 24 views
6

Ai đó có thể giải thích cho tôi tại sao mã sau không hoạt động?lỗi generics: không áp dụng cho các đối số

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

Tôi nhận được lỗi sau:

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

Tôi đã có nó để làm việc bằng cách thay đổi mã như sau:

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

nhưng tôi muốn hiểu tại sao bản gốc cách tiếp cận không hoạt động.

Trả lời

0

Điều đó không làm việc vì lớp học của bạn Client được viết cho không cụ thể Strategy (Strategy<?>) nhưng trong phương pháp run(), bạn vượt qua một String (đó là chỉ đúng cho Strategy<String>!). Điều đó sẽ chỉ hoạt động nếu bạn thay đổi thông số của a và thông số của setStrategy() thành loại Strategy<String>!

11

Câu trả lời rất đơn giản: không thể sử dụng ký tự đại diện không liên kết. Nó đơn giản có nghĩa là "đối tượng uknown".

Nó không cung cấp bất kỳ thông tin gì cho trình biên dịch. "?" phương tiện của bất cứ loại nào, vì vậy thực sự nó quá chung chung để có nghĩa là bất cứ điều gì.

Hãy xem ở đây: http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html

Như đã trình bày:

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

Vì chúng ta không biết những gì các loại nguyên tố của c là viết tắt của, chúng ta không thể thêm các đối tượng với nó. Phương thức add() nhận các đối số kiểu E, kiểu phần tử của bộ sưu tập. Khi tham số kiểu thực tế là?, Nó là viết tắt của một số loại không xác định. Bất kỳ tham số nào chúng tôi chuyển sang để thêm sẽ phải là một loại phụ của loại không xác định này. Vì chúng ta không biết loại đó là gì, chúng ta không thể truyền bất cứ thứ gì vào. Ngoại lệ duy nhất là null, là thành viên của mọi kiểu.

EDIT: đừng lo lắng, đây là sự hiểu lầm bình thường của ký tự đại diện java khi bạn bắt đầu sử dụng chúng. Đó là lý do tại sao các ký tự đại diện bị giới hạn (ví dụ: <? extends Something>) tồn tại, nếu không thì ký tự đại diện chung sẽ gần như vô dụng vì trình biên dịch không thể đưa ra bất kỳ giả định nào về nó.

0

Điều này là do đây không phải là loại hoạt động an toàn. "?" là một ký tự đại diện có nghĩa là tôi không biết loại. Nó không có nghĩa là "bất kỳ loại nào". đọc này ... http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf

Các vấn đề liên quan