2015-03-27 24 views
5

Tôi đã không google vấn đề này. Tại sao dòng này lại tạo ra một lỗi biên dịch.Mã với Generics sẽ không biên dịch

wrapper.doSmth(wrapper.getCurrent()); 

Tôi đang sử dụng java 7.

public class App { 
Wrapper<?> wrapper; 

class Generic<T>{ 

} 

class Wrapper<T>{ 
    Generic<T> current; 

    public void doSmth(Generic<T> generic){ 
    } 

    public Generic<T> getCurrent(){ 
    return current; 
    } 
} 

public void operation(){ 
    wrapper.doSmth(wrapper.getCurrent()); 
} 
} 

Lỗi này là:

Error:(25, 24) java: method doSmth in class App.Wrapper<T> cannot be applied to given types; 
    required: App.Generic<capture#1 of ?> 
    found: App.Generic<capture#2 of ?> 
    reason: actual argument App.Generic<capture#2 of ?> cannot be converted to conf.App.Generic<capture#1 of ?> by method invocation conversion 
+3

Bạn có thể đăng lỗi biên dịch thực tế không? – Waterbagel

+1

@Waterbagel Tôi đã chỉnh sửa bài đăng của mình để bao gồm thông báo lỗi – doctorgester

+0

Và có thể bạn có thể cho chúng tôi biết mã này được cho là như thế nào; bạn có ý định giải quyết vấn đề gì. – GhostCat

Trả lời

8

Các lỗi biên soạn nên một cái gì đó dọc theo dòng của "bắt giữ # 1 không? tương thích với capture? # 2 ". Nguyên nhân của lỗi này là wrapperWrapper<?>.

Trình biên dịch thấy rằng wrapper.getCurrent() trả về một Generic<?> và rằng wrapper.doSmth mất một tham số Generic<?>. Nhưng nó sẽ không cân bằng hai ký tự đại diện ?, ngay cả khi chúng ta có thể thấy rằng chúng đến từ cùng một cá thể và phải giống nhau.

Một giải pháp ở đây là tạo lớp chung là App, vì vậy bạn có thể thay thế ký tự đại diện.

public class App<T> { 

Bởi vì thực tế là GenericWrapper là lớp bên trong, T vẫn còn trong phạm vi, vì vậy bạn không cần phải khai báo một tham số kiểu generic cho họ nữa.

Wrapper wrapper; 

    class Generic{ 

    } 

    class Wrapper{ 
     Generic current; 

     public void doSmth(Generic generic){ 
     } 

     public Generic getCurrent(){ 
      return current; 
     } 
    } 

    public void operation(){ 
     wrapper.doSmth(wrapper.getCurrent()); 
    } 
} 
+0

"Nhưng nó sẽ không cân bằng hai ký tự đại diện, ngay cả khi chúng ta có thể thấy rằng chúng đến từ cùng một thể hiện và phải giống nhau." Đó là mục đích của câu hỏi của tôi. Có bất kỳ hậu cần đằng sau đó? – doctorgester

+0

'?' Có thể là bất cứ thứ gì, bất cứ lúc nào. Về mặt lý thuyết, một cái gì đó có thể trao đổi 'hiện tại' với cái gì đó có một tham số kiểu hoàn toàn khác. Có lẽ một cái gì đó có thể là một sợi mà làm cho nhiệm vụ đó trong 'hoạt động'. tl; dr Hai '?' s không bao giờ có thể tương đương. – rgettman

+0

Vâng, đó là điều duy nhất tôi giả định. Không thực sự hạnh phúc về điều đó. Cảm ơn bạn loại sir! – doctorgester

1

Có thể là công việc cho capturing helper.

public void operation() { 
    operationImpl(wrapper); 
} 

private static <T> void operationImpl(Wrapper<T> wrapper) { 
    wrapper.doSmth(wrapper.getCurrent()); 
} 

Không cần thay đổi gì khác. Người trợ giúp ghi lại loại wrapper để chúng tôi có thể chắc chắn getCurrent trả về cùng một loại như doSmth chấp nhận.


Lý do lỗi này xảy ra là mỗi lần một kiểu với một ký tự đại diện được gọi, một loại riêng biệt được giả định cho rằng điểm cụ thể trong biểu thức (gọi tắt là 'chụp'):

Wrapper<?> wrapper = ...; 

// each capture for T is assumed distinct from each other 
// vvvvvvv  vvvvvvv 
    wrapper.doSmth(wrapper.getCurrent()); 

Thực tế là điểm tham chiếu đến cùng một cá thể không liên quan đến cách chụp được chỉ định. Trình biên dịch không cần phải giải thích cho điều đó và một cái gì đó như thế này cũng có thể xảy ra

Wrapper<?> wrapper = new Wrapper<String>(); 
wrapper.doSmth((wrapper = new Wrapper<Float>()).getCurrent()); 

nơi T có thể thay đổi giữa biểu hiện.

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