2015-06-18 36 views
7

Tôi nhận được báo lỗi dưới đây:Tại sao phương thức này gọi không thành công? (Generics & ký tự đại diện)

'call(ContainsMonitor)' cannot invoke 'call(? extends webscout.Monitor)' in 'WebScoutCallable' 

Monitor.java

WebScoutCallable<? extends Monitor> handler; 

public setCallable(WebScoutCallable<? extends Monitor> callable) { 
    this.handler = callable; 
} 

WebScoutCallable.java

public interface WebScoutCallable<T extends Monitor> { 
    public void call(T caller); 
} 

ContainsMonitor.java

public class ContainsMonitor extends Monitor { 
    public void handleDocument() { 
      handler.call(this); 
    } 
} 

Tôi sẽ tự do thừa nhận rằng tôi mới sử dụng Generics và vẫn còn khá mới đối với Java. Tôi thấy thông báo lỗi gây nhầm lẫn vì có vẻ như nó sẽ hoạt động (khai báo phương thức mong đợi một Màn hình hoặc phân lớp, tôi đang chuyển vào một lớp con). Bất kỳ trợ giúp (+ giải thích) sẽ được đánh giá rất nhiều!

Cảm ơn!

Trả lời

6

Bạn có một ký tự đại diện trong tham số kiểu của biến handler của bạn. Trình biên dịch không biết loại chính xác của tham số kiểu này là gì, chỉ có nó là Monitor hoặc một lớp con.

Phương pháp call lấy số T, được khớp trên ký tự đại diện. Nhưng không có gì đảm bảo rằng loại ký tự đại diện là ContainsMonitor. Nó có thể là Monitor hoặc có thể là MonitorSubtypeThatDoesntExistYet. Bởi vì trình biên dịch không biết loại thực tế, nó không thể cho phép bạn vượt qua bất cứ điều gì ngoại trừ null, bởi vì với bất kỳ đối số không null, nó không thể đảm bảo an toàn loại.

Bạn có thể giải quyết vấn đề này bằng cách xóa ký tự đại diện và thay thế khái niệm đó bằng thông số loại trên lớp Monitor.

class Monitor<T extends Monitor<T>> 
{ 
    WebScoutCallable<T> handler; 

    public void setCallable(WebScoutCallable<T> callable) { 
     this.handler = callable; 
    } 
} 

Giao diện WebScoutCallable thay đổi một chút trong phản ứng:

interface WebScoutCallable<T extends Monitor<T>> { 
    public void call(T caller); 
} 

Các lớp con feeds tên riêng của mình như là đối số loại khi mở rộng Monitor.

class ContainsMonitor extends Monitor<ContainsMonitor> { 
    public void handleDocument() { 
      handler.call(this); 
    } 
} 

Bây giờ, T sẽ là một loại nổi tiếng, và ContainsMonitor định nghĩa nó là chính nó, để nó bây giờ pháp lý cho nó để vượt qua bản thân để call.

+0

Cảm ơn bạn đã trả lời chi tiết. Tôi nghĩ rằng có thể có một giải pháp ít tiết hơn nhưng điều này có ý nghĩa! – RNGuy

3

? extends Monitor có nghĩa là: một lớp con cụ thể của Màn hình, nhưng chúng tôi không biết cái nào. Vì vậy, nó có thể là ContainsMonitor hoặc không và handler có thể hoặc không thể chấp nhận ContainsMonitor. Trình biên dịch không thể quyết định và hiển thị lỗi.

Một cách để giải quyết vấn đề của bạn là sử dụng các loại cụ thể, ví dụ:

class Monitor<T extends Monitor<T>> { 
    WebScoutCallable<T> handler; 

    public setCallable(WebScoutCallable<T> callable) { 
    this.handler = callable; 
    } 
} 

class ContainsMonitor extends Monitor<ContainsMonitor> { 
    public void handleDocument() { 
    handler.call(this); 
    } 
} 
+0

Cảm ơn phản hồi nhanh. Ước gì tôi có thể đánh dấu hai giải pháp là chính xác! – RNGuy

-5

Mã của bạn không yêu cầu phải có generics.

public class Monitor { 
    WebScoutCallable handler; 

    public void setCallable(WebScoutCallable callable) { 
     this.handler = callable; 
    } 
} 

public interface WebScoutCallable { 
    public void call(Monitor caller); 
} 

public class ContainsMonitor extends Monitor { 
    public void handleDocument() { 
      handler.call(this); 
    } 
} 
+3

Điều này không trả lời câu hỏi của OP –

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