2008-12-20 37 views
9

Giả sử tôi có điều này:Cách thay thế dễ nhất cho một mảng chung trong Java là gì?

class test<T> 
{ 
    private T[] elements; 
    private int size; 
    public test(int size) 
    { 
     this.size = size; 
     elements = new T[this.size]; 
    } 
} 

vẻ như điều này là không thể vì trình biên dịch không biết những gì constructor để gọi một lần nó cố gắng thay thế mã Generics hoặc một cái gì đó. Những gì tôi đang tự hỏi là, làm thế nào tôi sẽ đi về việc này? Tôi tưởng tượng nó là có thể, cho như thế nào dễ dàng thực hiện nó là trong C + +.

Chỉnh sửa: Xin lỗi tôi đã quên [] trong tuyên bố thành phần.

Trả lời

0

Tôi có thể sai, nhưng tuyên bố của bạn có vẻ kỳ lạ, không nên bạn có:

private T[] elements; 
13

Vấn đề là kể từ khi tham số kiểu generic T được chuyển thành Object bởi trình biên dịch (nó được gọi là loại erasure), bạn thực sự tạo ra một mảng của Object. Những gì bạn có thể làm là cung cấp một Class<T> đến chức năng:

class test<T> 
{ 
    private T[] elements; 
    private int size; 
    public test(Class<T> type, int size) 
    { 
     this.size = size; 
     elements = (T[]) Array. newInstance(type, size); 
    } 
} 

Bạn sẽ tìm thấy một exlanation tốt hơn của nó ở đây: Angelika Langer - Can I create an array whose component type is a type parameter?

8

Các dễ nhất thay thế cho một mảng chung là sử dụng một danh sách.

+0

Tôi đồng ý - Danh sách thường là giải pháp thay thế tốt hơn vì nhiều lý do. Trong thực tế, một số người sẽ đề xuất rằng mảng nên được coi là một phần không được chấp nhận của ngôn ngữ trong Java 5+. Tôi không nói tôi là một trong số họ ... nhưng bạn sẽ tìm thấy ý kiến ​​đó. –

+0

Mảng vẫn hợp lệ đối với các kiểu nguyên thủy. Nhưng đối với các loại tham chiếu, nó chỉ là một tối ưu hóa không phù hợp hầu như mọi lúc. –

2

Có hai giải pháp không yêu cầu truyền trong đối tượng lớp. Trong cả hai tôi giả định rằng vì nó là một biến riêng, bạn là người duy nhất đưa mọi thứ vào nó, và thế giới bên ngoài không nhìn thấy nó.

Một là chỉ sử dụng mảng Đối tượng đơn giản Object[]. Điểm bất lợi là bạn sẽ mất đi những lợi ích của generics và bạn sẽ phải bỏ mọi thứ ra khỏi nó, điều này làm cho mã xấu hơn. Nhưng vì bạn là người duy nhất đưa mọi thứ vào đó, nên diễn viên nên luôn an toàn. Bên ngoài không cần phải biết chuyện gì đang diễn ra.

Các tùy chọn khác là loại hack. Bạn tạo một Object[] và sau đó "truyền" nó tới T[]. Về mặt kỹ thuật điều này là bất hợp pháp, bởi vì Object[]T[] là các loại thời gian chạy khác nhau và không thể truyền các loại thời gian này sang loại thời gian chạy khác. Nhưng miễn là bạn không chuyển mảng ra khỏi lớp (ví dụ: trả lại hoặc một thứ gì đó), thì nó sẽ không gây ra bất kỳ vấn đề nào, bởi vì T[] sẽ bị xóa thành Object[] và không thực hiện bất kỳ phép diễn nào. Sau đó, bạn có thể nhận được những lợi ích của generics trong lớp của bạn để dễ dàng hơn, nhưng bạn phải cực kỳ cẩn thận không vượt qua mảng đó cho bất cứ ai thực sự mong đợi một T[], bởi vì nó không phải là.

3

Tôi có xu hướng tránh các mảng cơ bản và sử dụng ArrayLists (hoặc tương tự Lists) ở bất kỳ nơi nào có thể vì một loạt lý do. Hai điều quan trọng nhất là:

  1. Tôi không cần ngữ nghĩa của mảng hói. Không có gì về ký hiệu khung (tức là, viết tắt cho số học con trỏ) làm cho cuộc sống của tôi dễ dàng hơn.

  2. Nếu tôi sử dụng Danh sách, tôi sẽ tự thiết lập để sử dụng các cấu trúc có khả năng tương thích phức tạp hơn xuống dòng, nếu cần. Ví dụ, nó chết dễ dàng để thay thế một ArrayList với một CopyOnWriteArrayList.

Vì vậy, viết ví dụ của bạn bằng cách sử dụng ArrayList chung sẽ giống như thế này:

lĩnh vực
class test<T> { 
    /** It's not strictly necessary to make this a List vs. an ArrayList 
     You decide what interface you really need to expose internally. */ 
    private List<T> elements; 
    /** This parameter isn't necessary with a List. You can always call the 
     size() method instead. */ 
    private int size; 
    public test(int size) { 
     this.size = size; 
     elements = new ArrayList<T>(); 
     // Note that the next line isn't strictly necessary. 
     // An ArrayList can be dynamically resized without any real effort on your part. 
     elements.ensureCapacity(size); 
    } 
} 
0

Kích thước không xuất hiện dư thừa. Bạn chỉ có thể có elements.length thay vì kích thước.

class Test<T> { 
    private final T[] elements; 
    public test(int size) { 
     elements = (T[]) new Object[size]; 
    } 
} 

Hoặc bạn có thể thay thế lớp Kiểm tra bằng ArrayList. tức là thả lớp hoàn toàn. cũng

+0

điều này sẽ ném một ngoại lệ vì mảng mới không thuộc loại T []. – pdeva

+0

@pdeva: không có; miễn là nó nằm trong lớp Test, nó sẽ không ném bất kỳ ngoại lệ nào vì việc xóa T [] là Object []; nhưng bạn phải cẩn thận đừng để nó rời khỏi lớp – newacct

0

Look để mã này:

public static <T> T[] toArray(final List<T> obj) { 
    if (obj == null || obj.isEmpty()) { 
     return null; 
    } 
    final T t = obj.get(0); 
    final T[] res = (T[]) Array.newInstance(t.getClass(), obj.size()); 
    for (int i = 0; i < obj.size(); i++) { 
     res[i] = obj.get(i); 
    } 
    return res; 
} 

Nó chuyển đổi một danh sách của bất kỳ loại đối tượng để một mảng cùng loại.

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