今天我們聊一聊java.lang.reflect包下的Array類,重點關注其中的newInstance方法。
1、Array類的簡單使用
java.lang.reflect包下除了提供Method(方法)、Constructor(構造器)、Filed(成員變量)這三個類,還提供了Array類,Array對象可以代表所有的數組,可通過Array類來動態創建數組,該類提供了以下類方法:
- static Object newInstance(Class<?> componentType, int... dimensions):創建指定元素類型、指定維度的數組。這裏的dimensions是可變個數的。
- static xxx getXxx(Object arr, int index):返回arr數組的第index位置元素。這裏xxx表示基本數據類型,比如getChar,getInt;若數組元素是引用類型,該方法變爲get((Object arr, int index)
- static void setXxx((Object arr, int index, xxx val):向arr數組的第index位置插入val值
對於上述方法,下面有個非常簡單的例子:
public class ReflectArrayTest {
public static void main(String args[]) {
try {
// 創建長度爲5,元素類型爲String的數組
Object arr = Array.newInstance(String.class, 5);
Array.set(arr, 3, "ttt");
Array.set(arr, 4, "fff");
Object obj = Array.get(arr, 3);
Object obj1 = Array.get(arr, 4);
} catch (Throwable e) {
System.err.println(e);
}
}
}
上述例子只是創建了簡單的一維數組,利用Array.newInstance還可以創建多維數組。
2、newInstance()方法返回值並不是泛型
在上述例子雖然創建String數組,但是其返回值只是簡單的Object對象,如果需要將arr對象當成String[]數組來用,就必須使用強轉:String[] cast = (String []) arr;,但是強轉是不安全的操作。而在反射中使用泛型Class<T>,可以有效避免強制類型轉化。
觀察Array的newInstance的方法簽名,可以觀察到奇怪的一點:
public static Object newInstance(Class<?> componentType, int... dimensions)
雖然方法簽名中使用了Class<?>泛型,但實際上並沒有真正利用泛型。如果將方法返回值改成如下形式:
public static <T> T[] newInstance(Class<T> componentType, int... dimensions) 這樣就可以在調用該方法後無需強制類型轉化了。不過改動了的這個方法只能暫時創建一維數組,就不能利用可變個數的參數優勢了。
我們可以將Array的newInstance方法封裝一下:
public class PackageArray {
// 強轉的時候,會有一個unchecked編譯警告,使用該註解可以抑制這個警告信息
@SuppressWarnings("unchecked")
public static <T> T[] newInstance(Class<T> componentType, int length) {
return (T[])Array.newInstance(componentType, length);
}
}
封裝後,調用PackageArray的newInstance類方法,就可直接獲取到具體元素類型的數組對象了。