java泛型怎么用反射生成_Java 之 使用反射生成并操作对象
一、使用反射創建對象
通過反射來生成對象有如下兩種方式:
方式一:
使用 Class 對象的 newInstance() 方法來創建 Class 對象對應類的實例,這種方法要求該 Class 對象的對應類有默認構造器,而執行 newInstance() 方法實際上是利用默認構造器來創建該類的實例。
方式二:
先使用 Class 對象獲取指定的 Constructor 對象,再調用 Constructor 對象的newInstance(Object... args) 方法來創建該 Class 對象對應類的實例。通過這種方式可以選擇使用某個類的指定構造器來創建實例。
通過第一種方式來創建對象是比較常見的情形,因為很多? JavaEE 框架中都需要根據配置文件信息來創建實例對象,從配置文件讀取的只是某個類的字符串類名,程序就需要根據該字符串來創建對應的實例,就必須使用反射。
代碼示例:
1 importjava.lang.reflect.Constructor;2
3 importorg.junit.Test;4
5 public classTestNewInstance {6 @Test7 public void test1() throwsException{8 Class> clazz = Class.forName("com.ks.reflect.Student");9 Object obj =clazz.newInstance();10 System.out.println(obj);11 }12
13 @Test14 public void test2() throwsException{15 Class> clazz = Class.forName("com.ks.reflect.Student");16 Constructor> constructor = clazz.getDeclaredConstructor(String.class);17 Object obj = constructor.newInstance("張三");18 System.out.println(obj);19 }20 }21 classStudent{22 privateString name;23
24 publicStudent(String name) {25 super();26 this.name =name;27 }28
29 publicStudent() {30 super();31 }32
33 @Override34 publicString toString() {35 return "Student [name=" + name + "]";36 }37 }
二、獲取或設置某個對象的屬性值
通過 Class 對象的 getFields() 等方法可以獲取該類所包括的全部 Field(屬性)或指定 Field。
而Field類除了提供獲取屬性的修飾符、屬性類型、屬性名等方法外,還提供了如下兩組方法來訪問屬性:
public xxx getXxx(Object obj):獲取obj對象該Field的屬性值
public void setXxx(Object obj,Xxx value):設置obj對象該Field的屬性值為value。
此處的XXX 對應 8 種基本數據類型,如果該屬性的類型是引用數據類型,則直接使用get(Object obj) 方法或 set(Object obj, Object value) 方法。
當屬性是 private不可訪問時,還需要下面的方法:
public void setAccessible(boolean flag)啟動和禁用訪問安全檢查的開關。
(1)值 true 則指示反射的對象在使用時應該取消 Java 語言訪問檢查。
提高反射的效率,如果代碼中必須用反射,而該句代碼需要頻繁的唄調用,那么請設置為 true
使得原本無法訪問的私有成員也可以訪問。
(2)值 false 則指示反射的對象應該實施 Java 語言訪問檢查。
Demo:獲取或設置某個對象的屬性值示例代碼
1 importjava.lang.reflect.Field;2
3 public classTestField {4
5 public static void main(String[] args)throwsException {6 Class> clazz = Class.forName("com.ks.reflect.Circle");7 Object obj =clazz.newInstance();8 Field field = clazz.getDeclaredField("radius");9 field.setAccessible(true);10 field.set(obj, 1.2);11 Object value =field.get(obj);12 System.out.println(value);13 }14
15 }16 classCircle{17 private doubleradius;18 }
三、調用方法
當獲得某個類對應的 Class 對象后,就可以通過該 Class 對象的 getMethods() 等方法獲取全部方法或指定方法。
每個 Method 對象對應一個方法,獲取 Method 對象后,程序就可以通過該 Method 對象的 invoke 方法來調用對應方法。
Object invoke(Object obj, Object... args):對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法
Demo:
1 importjava.lang.reflect.Method;2
3 public classTestMethod {4
5 public static void main(String[] args) throwsException {6 Class> clazz = Class.forName("com.ks.reflect.Utils");7 Object obj =clazz.newInstance();8 Method method = clazz.getMethod("check", String.class,String.class);9 Object value = method.invoke(obj, "tong","666");10 System.out.println(value);11 }12
13 }14 classUtils{15 public booleancheck(String user,String password){16 if("admin".equals(user) && "123".equals(password)){17 return true;18 }else{19 return false;20 }21 }22 }
注意:如果調用某個類的某個方法時,并不是傳入對象,而是 null,表示調用靜態方法。(即 invoke(null,參數列表))
四、操作數組
在java.lang.reflect包下還提供了一個Array類,Array對象可以代表所有的數組。程序可以通過使用Array類來動態的創建數組,操作數組元素等。
Array 類提供了如下幾個方法:
public static Object newInstance(Class> componentType, int... dimensions):創建一個具有指定的組件類型和維度的新數組
public static void setXxx(Object array,int index,xxx value):將array數組中[index]元素的值修改為value。
public static xxx getXxx(Object array,int index,xxx value):將array數組中[index]元素的值返回。
此處的 Xxx 對應 8 種基本數據類型,如果該屬性的類型是引用數據類型,則直接使用 set(object arr,int index, Object value)方法或 get(Object array, int index) 方法。
Demo:
1 importjava.lang.reflect.Array;2
3 public classTestArray {4 public static voidmain(String[] args) {5 Object arr = Array.newInstance(String.class, 5);6 Array.set(arr, 0, "Hello");7 Array.set(arr, 1, "World");8 System.out.println(Array.get(arr, 0));9 System.out.println(Array.get(arr, 1));10 System.out.println(Array.get(arr, 2));11 }12 }
五、運行時獲取注解信息
一個完整的注解,有三個要素:
(1)聲明
(2)使用
(3)讀取
像@Override,@SuppressWarings,@Deprecated等這些是JRE中聲明的,也是由編譯器讀取的
像@Test,@Before...等這些注解是JUnit聲明和讀取的
像@author,@param...等這些注解是JRE中聲明的,由javadoc.exe讀取的
對于自定義的注解,聲明和讀取需要自己完成
1、聲明注解
Demo:
1 //聲明注解
2 @Target({TYPE,FIELD})3 @Retention(RetentionPolicy.RUNTIME)//只有生命周期是運行時,那么才可以被反射讀取
4 @interfaceMyAnnotation{5 String value(); //如果配置參數只有一個,名稱是value,在使用時,賦值的話就可以省略"value="
6 String name(); //也可以使用 default 給它們指定默認值
7 }
2、使用注解
Demo:使用自定義的注解
1 //使用注解
2 @MyAnnotation(value = "Annotation",name="Java")3 classMyClass{4 @MyAnnotation(value="String",name="Field")5 privateString info;6
7 }
3、讀取注解
主要分為三步:
① 獲取 Class 對象
② 獲取注解對象
③ 獲取注解的配置參數的值
Demo:
1 public classTestAnnotation {2 @SuppressWarnings("unchecked")3 @Test4 public voidtest01() {5 //(1)獲取Class對象
6 Class clazz = MyClass.class;//四種方式之一7
8 //(2)獲取注解對象
9 MyAnnotation annotation = (MyAnnotation) clazz.getAnnotation(MyAnnotation.class);10
11 //(3)獲取注解的配置參數的值
12 String value =annotation.value();13 System.out.println("value = " +value);14
15 String name =annotation.name();16 System.out.println("name =" +name);17 }18
19 @SuppressWarnings("unchecked")20 @Test21 public void test02() throwsNoSuchFieldException, SecurityException {22 //(1)獲取Class對象
23 Class clazz = MyClass.class;//四種方式之一24
25 //(2)獲取屬性對象
26 Field infoField = clazz.getDeclaredField("info");27
28 //(3)獲取注解對象
29 MyAnnotation annotation = (MyAnnotation) infoField.getAnnotation(MyAnnotation.class);30
31 //(3)獲取注解的配置參數的值
32 String value =annotation.value();33 System.out.println("value = " +value);34
35 String name =annotation.name();36 System.out.println("name =" +name);37 }38
39 }
六、運行時讀取某個類的泛型實參
讀取某個類的泛型實參主要分為三步:
(1)獲取 Class 對象
(2)獲取泛型父類
Type type = clazz.getGenericSuperclass();
ParameterizedType type = (ParameterizedType) clazz.getGenericSuperclass();
(3)獲取類型實參
Type:代表Java的所有類型
(1)Class:代表的是普通的類型,沒有泛型信息的
(2)ParameterizedType:參數化類型? ? 例如:Father
(3)GenericArrayType:泛型數組類型? ?例如:T[]
(4)TypeVariable:類型變量? ? 例如:T
(5)WildcardType:帶?通配符的泛型的類型? 例如:ArrayList>??或ArrayList super 下限>?或ArrayList extends 上限>
Demo:
1 //泛型類型形參:
2 class Father{3
4 }5 //泛型類型實參:
6 class Son extends Father{7
8 }9
10 @Test11 public voidtest01() {12 //獲取Son類的泛型父類的類型實參13 //(1)獲取Class對象
14 Class clazz = Son.class;15
16 //(2)獲取泛型父類17 //獲取普通父類18 //Class fu = clazz.getSuperclass();19 //System.out.println(fu);20
21 //獲取泛型父類的參數
22 ParameterizedType type =(ParameterizedType) clazz.getGenericSuperclass();23
24 //(3)獲取類型實參
25 Type[] types =type.getActualTypeArguments();26 for(Type t : types) {27 System.out.println(t);28 }29 }
對于泛型類、接口的類型形參,什么時候才能確定具體的類型呢?
(1)創建它的對象
(2)繼承泛型類
(3)實現泛型接口
Demo:
1 class Tools{2 privateClass type;3
4 publicTools() {5 //在創建子類對象時,來確定type的代表類型6 //(1)獲取正在new的對象的類型Class對象
7 Class clazz = this.getClass();8
9 //(2)獲取泛型父類的信息
10 ParameterizedType t =(ParameterizedType) clazz.getGenericSuperclass();11
12 //(3)獲取類型實參
13 type = (Class) t.getActualTypeArguments()[0];14 }15
16
17 public voidtest(){18 //這個方法中需要用到T的類型對象,即T的Class對象19 //Class c = T.class;//此時無法確定T的類型
20 System.out.println(type);21 }22
23 }24 class MyTools extends Tools{25
26 }27
28 @Test29 public voidtest02() {30 MyTools my = newMyTools();31 my.test(); //class java.lang.String32
33 }
總結
以上是生活随笔為你收集整理的java泛型怎么用反射生成_Java 之 使用反射生成并操作对象的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java itext 导出pdf文件_【
- 下一篇: java中class.forname连接