2015-12-24 17 views
7

Tôi nhận được lỗi ClassCastException khi tôi chạy điều này vì diễn viên ngầm ẩn d thành gấp đôi khi tôi chạy mã. Tuy nhiên, nếu tôi thay đổi tham chiếu đến d thành Object[] thì nó không thể là tham số cho hàm được đặt. Nếu tôi thay đổi chức năng thiết lập để chấp nhận một Object[] thì mọi thứ hoạt động tốt, nhưng sau đó lớp sẽ thất bại trong thời gian chạy nếu có bất kỳ cuộc gọi nào được đặt trên một đối tượng không thuộc loại N.Trả lại một mảng từ một lớp chung

Tôi cần một giải pháp có thể get() mảng cũ (hoặc bản sao của chúng) và có thể set() dữ liệu vào một mảng mới.

public class Foo<N> { 

    public static void main(String[] args) { 
     Foo<Double> foo = new Foo<Double>(); 
     Double[] d = foo.get(); 

     // do stuff to d ... 

     foo.set(d); 
    } 

    N[] data; 

    public Foo() { 
     data = (N[]) new Object[2]; 
    } 

    public N[] get() { 
     return (N[]) data; 
    } 

    public void set(N[] data) { 
     this.data = data; 
    } 

} 
+1

Bản sao có thể có của [Cách tạo một mảng chung trong Java?] (Http://stackoverflow.com/questions/529085/how-to-create-a-generic-array-in-java) – Julien

+0

Nó không phải là một trùng lặp với q đó. – avisnacks

+0

bạn có thể sử dụng http: // stackoverflow này.com/a/3403976/2513573 để trích xuất loại và Array.newInstance để tạo mảng – AdamSkywalker

Trả lời

1

Để tạo một mảng có loại thời gian chạy phù hợp, yêu cầu một loại biểu diễn thời gian chạy của loại đó. Một lớp học chung chung như Foo<N> không có đại diện thời gian chạy là N.

Có hai giải pháp:

  1. Sử dụng một List<N> để thay thế. Điều này là tốt nhất nếu có thể!
  2. Thêm đại diện thời gian chạy theo cách thủ công N bằng cách chuyển vào một số Class<N> đến Foo, sử dụng java.lang.reflect.Array.newInstance để tạo mảng.

Mã cho các giải pháp thứ hai:

public Foo(Class<N> newDataClass) { 
    data = (N[]) Array.newInstance(newDataClass, 2); 
} 

Foo<Double> foo = new Foo<>(Double.class); 

EDIT:

Nếu những gì bạn muốn làm là thay vì để có được một bản sao của một Double mảng hiện tại bạn có thể làm với (N[]) data.clone(). Đặt nó sẽ không thành vấn đề.

1

Có một mẹo để làm điều này.

class Foo<N> { 

    // Deliberately no parameters. 
    N[] myArray = makeArray(); 

    private N[] makeArray(N... ns) { 
     return ns; 
    } 

    public N[] get() { 
     return myArray; 
    } 
} 

này có thể trông giống như không có đúc (đó là một điều tốt) nhưng thực sự có nghĩa là, nó chỉ là đang được thực hiện bởi hệ thống varargs.

+0

Có lẽ tôi không rõ ràng w câu hỏi nhưng trong trường hợp của tôi mảng đã được khởi tạo và tôi cần phải thực hiện một thay đổi cho nó. Vì vậy, tôi cần phải làm cho nó từ foo làm điều gì đó với nó. Và thiết lập lại nó. Tôi không thể có một giải pháp mà instantiates nó trong xây dựng. – avisnacks

+2

@avisnacks: Trong ví dụ của bạn, bạn tạo mảng trong hàm tạo 'Foo'. Đó không phải là cách nó hoạt động? Bạn có thể cập nhật câu hỏi để làm rõ hơn không? – Lii

+0

@OldCurmudgeon: Điều này không hoạt động. Bạn sẽ luôn nhận được một mảng 'Object' trong' myArray'. Khi initialiser gọi 'makeArray' không có dấu vết nào của' N' bên trái, nó đã bị xóa. Phương thức vararg chung luôn tạo mảng 'Object'. Không thể tạo các mảng kiểu generic. Điều đó được mô tả ví dụ trong [Hướng dẫn Java] (https://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#createArrays). – Lii

1

Cách thuận tiện (nhưng tiết) để thực hiện việc này là thay đổi hàm tạo để nhận đối số giả với loại mảng, vì bạn biết rằng nó gấp đôi phương pháp chính của bạn.

public class Foo<N> { 
     N[] data; 

     public Foo(N inType) { 
      data = (N[]) Array.newInstance(inType.getClass(), 2) ; 
     } 

     public N[] get() { 
      return (N[]) data; 
     } 

     public void set(N[] data) { 
      this.data = data; 
     } 

     public static void main(String[] args) { 
      Foo<Double> foo = new Foo<Double>(new Double(0)); 
      Double[] d = foo.get(); 
      // do stuff to d ... 
      foo.set(d); 
     } 

    } 
0

Vấn đề chung là không có loại cụ thể khi chạy. Nó chỉ là lớp Object, có nghĩa là, việc tạo ra đối tượng như vậy là hoàn toàn vô nghĩa, bởi vì bạn sẽ, trên thực tế, chỉ cần tạo một đối tượng kiểu Object.

Tuy nhiên, bạn có thể tạo các đối tượng như vậy từ bên ngoài lớp, vì loại đối tượng thực sự được biết ở đây (Double). Vì vậy, tôi sẽ đề nghị sử dụng một số loại List, có thể được năng động, để lưu trữ các giá trị.

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