2011-01-23 26 views
10

Trong Java, tại sao một mảng không thể là một ràng buộc của Biến kiểu, nhưng có thể là một ràng buộc của ký tự đại diện?Trong Java, tại sao một mảng không thể là một ràng buộc của Biến kiểu, nhưng có thể là một ràng buộc của Wildcard?

Bạn có thể có:

List< ? extends Integer[] > l; 

nhưng bạn không thể có:

class MyClass< T extends Integer[] > { } // ERROR! 

Tại sao?

+0

Thật lạ lùng. JLS khá rõ ràng nói rằng bạn chỉ có thể sử dụng các lớp hoặc giao diện trong các biến kiểu nhưng không đưa ra bất kỳ lời giải thích nào. – biziclop

+0

chỉ để thực hiện các so sánh tương tự: "Danh sách k1;" được cho phép, nhưng "Danh sách k2;" không phải là. Nhưng tôi không thể tìm thấy bất cứ điều gì ngoại trừ null để thêm vào danh sách! Eclipse cho biết k1.get (0) trả về kiểu Integer [], nhưng tôi không thể thêm một. –

Trả lời

7

xem xét mã này Java:

package test; 

public class Genric<E> 
{ 
    public Genric(E c){ 
     System.out.println(c.getClass().getName()); 
    } 
    public static void main(String[] args) { 
     new Genric<Integer[]>(new Integer[]{1,2}); 
    } 
} 

Đối với trường hợp đầu tiên của bạn:

List< ? extends Integer[] > l; 

Khi bạn làm điều gì đó như List< ? extends Integer[] > l; này sau đó trình biên dịch Java thấy nó như là một List< ? extends Object> l; và chuyển nó cho phù hợp . Vì vậy, đây là lý do tại sao bạn không nhận được bất kỳ lỗi nào.

Các tạo byte-code như sau:

. 
    . 
    . 
    20: aastore 
    21: invokespecial #52; //Method "<init>":(Ljava/lang/Object;)V 
    24: return 
    . 
    . 

Thanh toán số dòng . Mặc dù, tôi đã vượt qua một mảng java.lang.Integer; nội bộ nó được dịch sang java.lang.Object.

Đối với trường hợp thứ hai của bạn:

class MyClass< T extends Integer[] > { } // ERROR! 

Theo java ngôn ngữ đặc tả:

TypeParameter: 
TypeVariable TypeBoundopt 

TypeBound: 
extends ClassOrInterfaceType AdditionalBoundListopt 
. 
. 

Như bạn có thể thấy sự ràng buộc bao gồm duy nhất của lớp hoặc một giao diện (thậm chí không loại nguyên thủy). Vì vậy, khi bạn làm điều gì đó như thế này class MyClass< T extends Integer[] > { } thì Integer[] không đủ điều kiện làm lớp hoặc giao diện.

Theo sự hiểu biết của tôi về Java Spec, điều này đã được thực hiện để giải quyết tất cả các tình huống như

  1. class MyClass< T extends Integer[] >
  2. class MyClass< T extends Integer[][] >
  3. ..
  4. class MyClass< T extends Integer[][]...[] >

Bởi vì tất cả chúng có thể được biểu diễn là java.lang.Object và khi được chuyển làm thông số, như trong ví dụ

public Genric(E c){ 
      System.out.println(c.getClass().getName()); 
     } 

khi 'c' nhớ loại thật của nó.

Hy vọng điều này sẽ hữu ích.

+0

+1 cho đào vào by bytecode, mặc dù điều này vẫn giống như một lời giải thích của "hows" chứ không phải là "whys". Không phải là sự thay thế của tham số kiểu với 'Object' chỉ đơn giản là do loại erasure Ie 'List ' cũng sẽ trở thành một 'List ' trong bytecode phải không? Generic kiểu an toàn được kiểm tra chỉ bởi trình biên dịch trước khi xóa kiểu xảy ra. –

0

Bạn có thể làm một cái gì đó như:

public class MyClass<K> { 
    K array; 
    public MyClass(K k) { 
     array = k; 
    } 

Hoặc bạn có thể làm điều gì đó như thế này:

class MyClass< T extends Integer > { 
    ...make your variable MyClass[]... 
} 

Hope this helps và tôi không quá xa những gì bạn đã yêu cầu.

+0

Tôi tin rằng anh ta hỏi "TẠI SAO" không "LÀM THẾ NÀO ...": ( – Xorty

+0

Thật vậy. Tôi không cố gắng sử dụng một mảng như là một ràng buộc cho T. Chỉ muốn biết tại sao hạn chế này được áp dụng. –

+0

Xin lỗi vì Nếu bạn cho tôi biết cách xóa bài đăng này, tôi sẽ loại bỏ nó vì nó không liên quan. – 4everAStudent

3

Tôi đang cố gắng để suy nghĩ về lý do cụ thể này nên bị cấm nhưng là người duy nhất tôi có thể nghĩ là nó là một cấu trúc hoàn toàn không cần thiết, bởi vì:

class Foo<T extends Integer[]> { 
    T bar(); 
} 

tương đương với

class Foo<T extends Integer> { 
    T[] bar(); 
} 

Rõ ràng điều tương tự không thể nói về trường hợp ký tự đại diện, do đó nó được cho phép ở đó.

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