2010-10-13 36 views
39

Tôi có một phương pháp trong khuôn khổ thử nghiệm của tôi tạo ra một thể hiện của một lớp học, tùy thuộc vào các thông số được thông qua vào:Java Reflection gọi constructor với các loại nguyên thủy

public void test(Object... constructorArgs) throws Exception { 
    Constructor<T> con; 
    if (constructorArgs.length > 0) { 
     Class<?>[] parameterTypes = new Class<?>[constructorArgs.length]; 
     for (int i = 0; i < constructorArgs.length; i++) { 
      parameterTypes[i] = constructorArgs[i].getClass(); 
     } 
     con = clazz.getConstructor(parameterTypes); 
    } else { 
     con = clazz.getConstructor(); 
    } 
} 

Vấn đề là, điều này không có tác dụng nếu các nhà xây dựng có các kiểu dữ, như sau:

public Range(String name, int lowerBound, int upperBound) { ... } 

.test("a", 1, 3); 

Kết quả trong:

java.lang.NoSuchMethodException: Range.<init>(java.lang.String, java.lang.Integer, java.lang.Integer) 

Th e int nguyên thủy được tự động đóng hộp trong các phiên bản đối tượng, nhưng làm thế nào để tôi lấy lại chúng để gọi hàm tạo?

Trả lời

121

Sử dụng Integer.TYPE thay vì Integer.class.

Theo Javadocs, đây là "Cá thể lớp thể hiện kiểu nguyên thủy int".

Bạn cũng có thể sử dụng int.class. Đó là lối tắt cho Integer.TYPE. Không chỉ các lớp, ngay cả đối với các kiểu nguyên thủy, bạn có thể nói type.class trong Java.

+10

int.class là một phím tắt cho Integer.TYPE, đối với bất kỳ, thậm chí kiểu nguyên thủy trong Java bạn có thể viết: type.class – iirekm

+1

Điều này được cho là một câu trả lời được chấp nhận. Bạn đánh bại Plaudit Design vài giây ;-) Chỉ cần chỉnh sửa để bao gồm bình luận của iirekm. –

18

Để tham chiếu các kiểu dữ liệu sử dụng, ví dụ:

Integer.TYPE; 

Bạn sẽ cần phải biết đối số được truyền vào phương pháp của bạn là những giá trị nguyên thủy. Bạn có thể làm điều này với:

object.getClass().isPrimitive() 
2

Nếu giá trị nguyên thủy int được autoboxed vào Integer đối tượng, nó không phải là nguyên thủy nữa. Bạn không thể kể từ ví dụ Integer cho dù đó là int tại một thời điểm nào đó.

Tôi khuyên bạn nên chuyển hai mảng vào phương thức test: một với các loại và một có giá trị. Nó cũng sẽ loại bỏ sự mơ hồ nếu bạn có một hàm tạo MyClass(Object) và vượt qua giá trị chuỗi (getConstructor sẽ tìm kiếm hàm tạo String).
Ngoài ra, bạn không thể nói loại tham số được mong đợi nếu giá trị tham số là null.

+0

'nếu giá trị int nguyên thủy được autoboxed vào đối tượng Integer, nó không còn nguyên thủy nữa. Bạn không thể nói từ ví dụ Integer cho dù đó là int tại một số điểm' đã không nhận được điểm này của bạn với câu hỏi. nếu một nguyên thủy được đóng hộp để Integer hơn lý do tại sao nó không giải quyết cho var args –

+0

@ org.life.java Bạn có ý nghĩa gì, _ "không giải quyết cho var args" _? Lỗi là do hàm tạo không thể được tìm thấy. Phần Vararg hoạt động trơn tru, _int_ được chuyển thành _Integer_ cho phần tử thứ hai và thứ ba của mảng _constructorArgs_ (vì lý do đơn giản là _int_ không thể ba phần của _Object [] _). –

+0

ow ... Xin lỗi đã hiểu nhầm Câu hỏi. vẫn Q. không rõ ràng :) –

4

Vì các kiểu gốc được tự động hóa, cuộc gọi getConstructor(java.lang.Class<?>... parameterTypes) sẽ không thành công. Bạn sẽ cần phải tự lặp qua các nhà xây dựng có sẵn. Nếu tất cả các loại phù hợp thì bạn ổn. Nếu một số loại không khớp, nhưng kiểu được yêu cầu là kiểu nguyên thủy và kiểu có sẵn là lớp trình bao bọc tương ứng, thì bạn có thể sử dụng hàm tạo đó. Xem dưới đây:

static <C> Constructor<C> getAppropriateConstructor(Class<C> c, Object[] initArgs){ 
    if(initArgs == null) 
     initArgs = new Object[0]; 
    for(Constructor con : c.getDeclaredConstructors()){ 
     Class[] types = con.getParameterTypes(); 
     if(types.length!=initArgs.length) 
      continue; 
     boolean match = true; 
     for(int i = 0; i < types.length; i++){ 
      Class need = types[i], got = initArgs[i].getClass(); 
      if(!need.isAssignableFrom(got)){ 
       if(need.isPrimitive()){ 
        match = (int.class.equals(need) && Integer.class.equals(got)) 
        || (long.class.equals(need) && Long.class.equals(got)) 
        || (char.class.equals(need) && Character.class.equals(got)) 
        || (short.class.equals(need) && Short.class.equals(got)) 
        || (boolean.class.equals(need) && Boolean.class.equals(got)) 
        || (byte.class.equals(need) && Byte.class.equals(got)); 
       }else{ 
        match = false; 
       } 
      } 
      if(!match) 
       break; 
     } 
     if(match) 
      return con; 
    } 
    throw new IllegalArgumentException("Cannot find an appropriate constructor for class " + c + " and arguments " + Arrays.toString(initArgs)); 
} 
+0

Bạn đã quên các loại dấu phẩy động. – Lii

3

bạn có thể viết

int[].class.getComponentType() 

hoặc

Integer.TYPE 

hoặc

int.class 
+0

cho câu trả lời đơn giản và rõ ràng – nahab

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