一、背景
最近的專案中需要使用到Java 反射的知識,以前不怎麼了解,也基本沒怎麼用過,抽出一片時間,來具體學習和實戰下Java的反射!拿來和大家分享以及記錄方便以後學習!
二、反射相關概念解析
1.Class類
Class類:Java程式中的各個Java類屬於同一類事物,描述這類事物的Java類名就是Class。
如何得到各個類的位元組碼即Class類呢?
[1].類名.class:直接通過類.class獲得。
[2].物件.getClass():通過物件呼叫其getClass方法獲得。
[3].Class.forName("類全路徑"):通過類載入器載入獲得
注:Java中的原始基本型別:boolean, byte
, char
, short
, int
, long
, float
,double和關鍵詞 void同樣都有Class類,通過.class可獲得它們的類位元組碼。
2.反射的概念
反射就是把Java類中的各種成分對映成相應的Java類,例如一個Java類中用一個Class類的物件表示一個類中的組成部分:成員變數,方法,構造方法,包等等資訊也用一個個的Java類來表示,例如人是一個類,那麼人的大腦、雙手等也是一個個類。表示Java的Class類顯然要提供一系列的方法,來獲得其中的變數、方法、構造方法,修飾符、包等資訊,這些資訊就是用相應的類的例項物件來表示,他們是Field、Method、Contructor、Package等等。
一個類中的每個成員都可以用相應的反射API類的一個例項物件來表示。
三、反射實戰
測試Bean:Person.java
1 package com.hafiz.zhang.Bean; 2 3 public class Person { 4 public Integer id; 5 private String name; 6 7 public Person() { 8 } 9 public Person(Integer id, String name) { 10 super(); 11 this.id = id; 12 this.name = name; 13 } 14 public Integer getId() { 15 return id; 16 } 17 public void setId(Integer id) { 18 this.id = id; 19 } 20 public String getName() { 21 return name; 22 } 23 public void setName(String name) { 24 this.name = name; 25 } 26 @Override 27 public String toString() { 28 return "Person [id=" + id + ", name=" + name + "]"; 29 } 30 31 public void sayHello() throws Exception{ 32 System.out.println("Hello Reflect!"); 33 } 34 }
1.使用反射獲取物件所屬類的全路徑(包括報名和類名)
1 package com.hafiz.zhang.test; 2 3 import com.hafiz.zhang.Bean.Person; 4 5 /** 6 * @author hafiz.Zhang 7 * @Date 2016年5月18日 下午4:28:35 8 * @Description 測試通過一個物件獲取該物件所屬於的類的全路徑(包括完整包名和類名) 9 */ 10 public class ReflectTest1 { 11 public static void main(String[] args) { 12 Person person = new Person(); 13 System.out.println("ClassName = " + person.getClass().getName()); 14 } 15 }
測試結果:
ClassName = com.hafiz.zhang.Bean.Person
2.測試使用反射例項化Class類物件
1 package com.hafiz.zhang.test; 2 3 import com.hafiz.zhang.Bean.Person; 4 5 /** 6 * @author hafiz.Zhang 7 * @Date 2016年5月18日 下午4:31:36 8 * @Description 測試獲取Class類的三種方式 9 */ 10 public class ReflectTest2 { 11 public static void main(String[] args) { 12 Class<?> obj1 = null; 13 Class<?> obj2 = null; 14 Class<?> obj3 = null; 15 try { 16 //一般儘量要採用這種方式進行例項化Class類物件 17 obj1 = (Class<?>) Class.forName("com.hafiz.zhang.Bean.Person"); 18 } catch (ClassNotFoundException e) { 19 e.printStackTrace(); 20 } 21 obj2 = new Person().getClass(); 22 obj3 = Person.class; 23 24 System.out.println("ClassName:" + obj1.getName()); 25 System.out.println("ClassName:" + obj2.getName()); 26 System.out.println("ClassName:" + obj3.getName()); 27 } 28 }
測試結果:
ClassName:com.hafiz.zhang.Bean.Person
ClassName:com.hafiz.zhang.Bean.Person
ClassName:com.hafiz.zhang.Bean.Person
3.測試通過Class類物件例項化其他類
1 package com.hafiz.zhang.test; 2 3 import com.hafiz.zhang.Bean.Person; 4 5 /** 6 * @author hafiz.Zhang 7 * @Date 2016年5月18日 下午4:38:15 8 * @Description 測試通過Class類物件例項化其他類 9 */ 10 public class ReflectTest3 { 11 public static void main(String[] args) { 12 Class<?> clazz = null; 13 try { 14 clazz = Class.forName("com.hafiz.zhang.Bean.Person"); 15 } catch (ClassNotFoundException e) { 16 e.printStackTrace(); 17 } 18 Person person = null; 19 try { 20 person = (Person) clazz.newInstance(); 21 } catch (InstantiationException e) { 22 e.printStackTrace(); 23 } catch (IllegalAccessException e) { 24 e.printStackTrace(); 25 } 26 if(null != person) { 27 person.setId(1); 28 person.setName("Hafiz.Zhang"); 29 System.out.println("person=" + person); 30 }else{ 31 System.out.println("例項化物件失敗"); 32 } 33 } 34 }
測試結果:
person=Person [id=1, name=Hafiz.Zhang]
4.測試通過Class呼叫其他類中的建構函式 (也可以通過這種方式通過Class建立其他類的物件)
1 package com.hafiz.zhang.test; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.InvocationTargetException; 5 6 import com.hafiz.zhang.Bean.Person; 7 8 /** 9 * @author hafiz.Zhang 10 * @Date 2016年5月18日 下午4:42:08 11 * @Description 測試通過Class呼叫其他類中的建構函式 (也可以通過這種方式通過Class建立其他類的物件) 12 */ 13 public class ReflectTest4 { 14 public static void main(String[] args) { 15 Class<?> clazz = null; 16 try { 17 clazz = Class.forName("com.hafiz.zhang.Bean.Person"); 18 } catch (ClassNotFoundException e) { 19 e.printStackTrace(); 20 } 21 Person p1 = null; 22 Person p2 = null; 23 Constructor<?>[] cs = clazz.getConstructors(); 24 try { 25 p1 = (Person) cs[0].newInstance();//通過無參構造獲得物件 26 p2 = (Person) cs[1].newInstance(1, "Hafiz.Zhang");//通過有參構造獲得物件 27 } catch (InstantiationException e) { 28 e.printStackTrace(); 29 } catch (IllegalAccessException e) { 30 e.printStackTrace(); 31 } catch (IllegalArgumentException e) { 32 e.printStackTrace(); 33 } catch (InvocationTargetException e) { 34 e.printStackTrace(); 35 } 36 System.out.println("Person1=" + p1); 37 System.out.println("Person2=" + p2); 38 } 39 }
測試結果:
Person1=Person [id=null, name=null]
Person2=Person [id=1, name=Hafiz.Zhang]
5.測試使用反射獲取一個類實現的介面
介面Animal.java
1 package com.hafiz.zhang.Bean; 2 3 /** 4 * @author hafiz.Zhang 5 * @Date 2016年5月19日 下午6:13:37 6 * @Description 動物介面 7 */ 8 public interface Animal { 9 public abstract void eat(); 10 public abstract void sleep(); 11 }
介面Skill.java
1 package com.hafiz.zhang.Bean; 2 3 /** 4 * @author hafiz.Zhang 5 * @Date 2016年5月19日 下午6:14:06 6 * @Description 技能介面 7 */ 8 public interface Skill { 9 public abstract void sayMiao(); 10 }
實現類:Cat.java
1 package com.hafiz.zhang.Bean; 2 3 public class Cat implements Animal, Skill { 4 private Integer num; 5 private String desc; 6 public Integer getNum() { 7 return num; 8 } 9 10 public void setNum(Integer num) { 11 this.num = num; 12 } 13 14 public String getDesc() { 15 return desc; 16 } 17 18 public void setDesc(String desc) { 19 this.desc = desc; 20 } 21 22 @Override 23 public void eat() { 24 System.out.println("cat eat fish"); 25 } 26 27 @Override 28 public void sleep() { 29 System.out.println("cat sleep in the day"); 30 } 31 32 @Override 33 public void sayMiao() { 34 System.out.println("cat say miao"); 35 } 36 37 public void sayHello(String name){ 38 System.out.println("Hello " + name); 39 } 40 }
測試類
1 package com.hafiz.zhang.test; 2 3 /** 4 * @author hafiz.Zhang 5 * @Date 2016年5月18日 下午4:51:29 6 * @Description 測試使用反射獲取一個類實現的介面 7 */ 8 public class ReflectTest5 { 9 public static void main(String[] args) { 10 Class<?> clazz = null; 11 try { 12 clazz = Class.forName("com.hafiz.zhang.Bean.Cat"); 13 } catch (ClassNotFoundException e) { 14 e.printStackTrace(); 15 } 16 Class<?>[] interfaces = clazz.getInterfaces(); 17 System.out.println("Cat實現的介面有"); 18 for(Class<?> cl : interfaces) { 19 System.out.println(cl.getName()); 20 } 21 } 22 }
測試結果:
Cat實現的介面有
com.hafiz.zhang.Bean.Animal
com.hafiz.zhang.Bean.Skill
6.測試通過反射取得指定類的父類
1 package com.hafiz.zhang.test; 2 3 /** 4 * @author hafiz.Zhang 5 * @Date 2016年5月18日 下午5:03:25 6 * @Description 測試通過反射取得指定類的父類 7 */ 8 public class ReflectTest6 { 9 public static void main(String[] args) { 10 Class<?> clazz = null; 11 try { 12 clazz = Class.forName("com.hafiz.zhang.Bean.Cat"); 13 } catch (ClassNotFoundException e) { 14 e.printStackTrace(); 15 } 16 Class<?> superClass = clazz.getSuperclass(); 17 System.out.println("SuperClass=" + superClass); 18 } 19 }
測試結果:SuperClass=class com.hafiz.zhang.Bean.Person
7.測試通過反射獲得其他類中的全部建構函式
1 package com.hafiz.zhang.test; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Modifier; 5 6 /** 7 * @author hafiz.Zhang 8 * @Date 2016年5月18日 下午5:06:02 9 * @Description 測試通過反射獲得其他類中的全部建構函式 10 */ 11 public class ReflectTest7 { 12 public static void main(String[] args) { 13 Class<?> clazz = null; 14 try { 15 clazz = Class.forName("com.hafiz.zhang.Bean.Person"); 16 } catch (ClassNotFoundException e) { 17 e.printStackTrace(); 18 } 19 Constructor<?>[] cs = clazz.getConstructors(); 20 //實現方式1 21 /*for(Constructor<?> item : cs) { 22 System.out.println("構造方法:" + item.getName()); 23 }*/ 24 //實現方式2 25 for(Constructor<?> item : cs) { 26 System.out.print("構造方法:"); 27 System.out.print(Modifier.toString(item.getModifiers()) + " "); 28 System.out.print(item.getName() + "("); 29 Class<?>[] paramterTypes = item.getParameterTypes(); 30 for(int i = 0; i < paramterTypes.length; i++) { 31 System.out.print(paramterTypes[i].getName() + " arg" + i); 32 if(i < paramterTypes.length-1) { 33 System.out.print(","); 34 } 35 } 36 System.out.println(")"); 37 } 38 } 39 }
測試結果:
構造方法:public com.hafiz.zhang.Bean.Person()
構造方法:public com.hafiz.zhang.Bean.Person(java.lang.Integer arg0,java.lang.String arg1)
8. 測試通過反射獲取類中的所有方法(包括方法包含的異常)
1 package com.hafiz.zhang.test; 2 3 import java.lang.reflect.Method; 4 import java.lang.reflect.Modifier; 5 6 /** 7 * @author hafiz.Zhang 8 * @Date 2016年5月18日 下午5:22:51 9 * @Description 測試通過反射獲取類中的所有方法 10 */ 11 public class ReflectTest8 { 12 public static void main(String[] args) { 13 Class<?> clazz = null; 14 try { 15 clazz = Class.forName("com.hafiz.zhang.Bean.Person"); 16 } catch (ClassNotFoundException e) { 17 e.printStackTrace(); 18 } 19 Method[] methods = clazz.getDeclaredMethods(); 20 for(Method method : methods) { 21 Class<?> returnType = method.getReturnType(); 22 System.out.print(Modifier.toString(method.getModifiers()) + " "); 23 System.out.print(returnType.getName() + " " + method.getName() + "("); 24 Class<?>[] paras = method.getParameterTypes(); 25 for(int i = 0 ; i < paras.length ; i++) { 26 System.out.print(paras[i].getName() + " arg" + i); 27 if(i < paras.length - 1) { 28 System.out.print(","); 29 } 30 } 31 Class<?>[] exces = method.getExceptionTypes(); 32 if(exces.length > 0) { 33 System.out.print(") throws "); 34 for(int j = 0; j < exces.length; j++) { 35 System.out.print(exces[j].getName()); 36 if(j < exces.length - 1) { 37 System.out.print(", "); 38 } 39 } 40 }else{ 41 System.out.print(")"); 42 } 43 System.out.println(); 44 } 45 } 46 }
測試結果:
public java.lang.String toString()
public java.lang.String getName()
public void setName(java.lang.String arg0)
public java.lang.Integer getId()
public void sayHello() throws java.lang.Exception
public void setId(java.lang.Integer arg0)
9.測試通過反射獲取類中所有的屬性
1 package com.hafiz.zhang.test; 2 3 import java.lang.reflect.Field; 4 import java.lang.reflect.Modifier; 5 6 /** 7 * @author hafiz.Zhang 8 * @Date 2016年5月18日 下午5:38:09 9 * @Description 測試通過反射獲取類中所有的屬性 10 */ 11 public class ReflectTest9 { 12 public static void main(String[] args) { 13 Class<?> clazz = null; 14 try { 15 clazz = Class.forName("com.hafiz.zhang.Bean.Cat"); 16 } catch (ClassNotFoundException e) { 17 e.printStackTrace(); 18 } 19 Field[] fields = clazz.getDeclaredFields(); 20 System.out.println("=========通過反射獲取指定類中所有的屬性========="); 21 for(Field field : fields) { 22 System.out.println(Modifier.toString(field.getModifiers()) + " " + field.getType().getName() + " " + field.getName()); 23 } 24 System.out.println("=========通過反射獲取指定類實現的介面或者父類中所有的屬性========="); 25 Field[] fields2 = clazz.getSuperclass().getDeclaredFields(); 26 for(Field item : fields2) { 27 System.out.println(Modifier.toString(item.getModifiers()) + " " + item.getType() + " " + item.getName()); 28 } 29 } 30 }
測試結果:
=========通過反射獲取指定類中所有的屬性=========
private java.lang.Integer num
private java.lang.String desc
=========通過反射獲取指定類實現的介面或者父類中所有的屬性=========
public class java.lang.Integer id
private class java.lang.String name
10.測試使用反射呼叫指定類的方法
1 package com.hafiz.zhang.test; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 6 /** 7 * @author hafiz.Zhang 8 * @Date 2016年5月19日 下午3:22:33 9 * @Description 測試使用反射呼叫指定類的方法 10 */ 11 public class ReflectTest10 { 12 public static void main(String[] args) { 13 Class<?> clazz = null; 14 try { 15 clazz = Class.forName("com.hafiz.zhang.Bean.Cat"); 16 } catch (ClassNotFoundException e) { 17 e.printStackTrace(); 18 } 19 try { 20 //呼叫Cat類中的eat無參方法 21 Method method = clazz.getMethod("eat"); 22 method.invoke(clazz.newInstance()); 23 //呼叫Cat類中的sayHello有參方法 24 Method method2 = clazz.getDeclaredMethod("sayHello", String.class); 25 method2.invoke(clazz.newInstance(), "Hafiz.Zhang"); 26 } catch (NoSuchMethodException e) { 27 e.printStackTrace(); 28 } catch (SecurityException e) { 29 e.printStackTrace(); 30 } catch (IllegalAccessException e) { 31 e.printStackTrace(); 32 } catch (IllegalArgumentException e) { 33 e.printStackTrace(); 34 } catch (InvocationTargetException e) { 35 e.printStackTrace(); 36 } catch (InstantiationException e) { 37 e.printStackTrace(); 38 } 39 } 40 }
測試結果:
cat eat fish
Hello Hafiz.Zhang
11.測試通過反射呼叫其他類中的setter和getter方法
1 package com.hafiz.zhang.test; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 6 /** 7 * @author hafiz.Zhang 8 * @Date 2016年5月19日 下午3:29:34 9 * @Description 測試通過反射呼叫其他類中的setter和getter方法 10 */ 11 public class ReflectTest11 { 12 public static void main(String[] args) { 13 Class<?> clazz = null; 14 Object obj = null; 15 try { 16 clazz = Class.forName("com.hafiz.zhang.Bean.Cat"); 17 obj = clazz.newInstance(); 18 } catch (ClassNotFoundException e) { 19 e.printStackTrace(); 20 } catch (InstantiationException e) { 21 e.printStackTrace(); 22 } catch (IllegalAccessException e) { 23 e.printStackTrace(); 24 } 25 getter(obj,"Desc"); 26 setter(obj,"Desc","測試呼叫set方法",String.class); 27 getter(obj,"Desc"); 28 } 29 30 private static void getter(Object obj, String name) { 31 try { 32 Method method = obj.getClass().getMethod("get"+name); 33 System.out.println(name + ":" + method.invoke(obj)); 34 } catch (NoSuchMethodException e) { 35 e.printStackTrace(); 36 } catch (SecurityException e) { 37 e.printStackTrace(); 38 } catch (IllegalAccessException e) { 39 e.printStackTrace(); 40 } catch (IllegalArgumentException e) { 41 e.printStackTrace(); 42 } catch (InvocationTargetException e) { 43 e.printStackTrace(); 44 } 45 } 46 47 private static void setter(Object obj, String name, String desc, Class<?> type) { 48 try { 49 Method method = obj.getClass().getMethod("set" + name, type); 50 method.invoke(obj, desc); 51 } catch (NoSuchMethodException e) { 52 e.printStackTrace(); 53 } catch (SecurityException e) { 54 e.printStackTrace(); 55 } catch (IllegalAccessException e) { 56 e.printStackTrace(); 57 } catch (IllegalArgumentException e) { 58 e.printStackTrace(); 59 } catch (InvocationTargetException e) { 60 e.printStackTrace(); 61 } 62 } 63 }
測試結果:
Desc:null
Desc:測試呼叫set方法
12.測試通過反射操作屬性
1 package com.hafiz.zhang.test; 2 3 import java.lang.reflect.Field; 4 5 /** 6 * @author hafiz.Zhang 7 * @Date 2016年5月19日 下午3:41:59 8 * @Description 測試通過反射操作屬性 9 */ 10 public class ReflectTest12 { 11 public static void main(String[] args) { 12 Class<?> clazz = null; 13 Object obj = null; 14 try { 15 clazz = Class.forName("com.hafiz.zhang.Bean.Cat"); 16 obj = clazz.newInstance(); 17 Field field = clazz.getDeclaredField("desc"); 18 //若要設定private屬性,需要設定 19 field.setAccessible(true);//設定成員變數可訪問,包括private成員變數(暴力反射),private成員通過這步操作才能被訪問 20 field.set(obj, "this is test demo"); 21 System.out.println("Desc=" + field.get(obj)); 22 } catch (ClassNotFoundException e) { 23 e.printStackTrace(); 24 } catch (InstantiationException e) { 25 e.printStackTrace(); 26 } catch (IllegalAccessException e) { 27 e.printStackTrace(); 28 } catch (NoSuchFieldException e) { 29 e.printStackTrace(); 30 } catch (SecurityException e) { 31 e.printStackTrace(); 32 } 33 34 } 35 }
測試結果:Desc=this is test demo
13.測試通過反射進行陣列操作
1 package com.hafiz.zhang.test; 2 3 import java.lang.reflect.Array; 4 5 /** 6 * @author hafiz.Zhang 7 * @Date 2016年5月19日 下午4:52:21 8 * @Description 測試通過反射進行陣列操作 9 * 10 */ 11 public class ReflectTest13 { 12 public static void main(String[] args) { 13 Integer[] array = {1,2,3,4,5,6}; 14 Class<?> clazz = array.getClass().getComponentType(); 15 System.out.println("陣列型別:" + clazz.getName()); 16 System.out.println("陣列長度:" + Array.getLength(array)); 17 System.out.println("陣列第一個元素:" + Array.get(array, 0)); 18 Array.set(array, 0, 8); 19 System.out.println("修改之後陣列第一個元素:" + Array.get(array, 0)); 20 System.out.println("=============反射修改陣列長度================="); 21 Integer[] arr2 = (Integer[])changeLength(array, 10); 22 print(arr2); 23 } 24 private static void print(Object obj) { 25 Class<?> clazz = obj.getClass(); 26 if(!clazz.isArray()) { 27 return; 28 } 29 System.out.println("陣列長度為:" + Array.getLength(obj)); 30 for(int i = 0; i < Array.getLength(obj); i++){ 31 System.out.print(Array.get(obj, i) + " "); 32 } 33 } 34 public static Object changeLength(Object obj, Integer length){ 35 Class<?> clazz = obj.getClass().getComponentType(); 36 Object newArr = Array.newInstance(clazz, length); 37 Integer len = Array.getLength(obj); 38 System.arraycopy(obj, 0, newArr, 0, len); 39 return newArr; 40 } 41 }
測試結果:
陣列型別:java.lang.Integer
陣列長度:6
陣列第一個元素:1
修改之後陣列第一個元素:8
=============反射修改陣列長度=================
陣列長度為:10
8 2 3 4 5 6 null null null null