JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;
Java反射機制主要提供了以下功能: 在運行時判斷任意一個對象所屬的類;在運行時構造任意一個類的對象;在運行時判斷任意一個類所具有的成員變量和方法;在運行時調用任意一個對象的方法;生成動態代理。
Class反射機制
- 指的是可以於運行時加載,探知和使用編譯期間完全未知的類.
- 程序在運行狀態中,可以動態加載一個只有名稱的類,對於任意一個已經加載的類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能調用他的任意一個方法和屬性;
- 加載完類之後,在堆內存中會產生一個Class類型的對象(一個類只有一個Class對象),這個對象包含了完整的類的結構信息,而且這個Class對象就像一面鏡子,透過這個鏡子看到類的結構,所以被稱之爲:反射。
- 每個類被加載進入內存之後,系統就會爲該類生成一個對應的java.lang.Class對象,通過該Class對象就可以訪問到JVM中的這個類.
Class對象的獲取
- 對象的getClass()方法;
- 類的.class(最安全/性能最好)屬性;
- 運用Class.forName(String className)動態加載類,className需要是類的全限定名(最常用).
- package com.lwl.reflect;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- /**
- * 獲取類的所有屬性和方法及構造器
- * @create 2017-10-11 上午11:42:52
- * @version 1.0
- */
- public class ReflectAllDemo {
- /**
- * 獲取類的所有屬性和方法及構造器
- * @param args
- * @throws ClassNotFoundException
- * @create 2017-10-11 上午9:07:46
- */
- public static void main(String[] args) throws ClassNotFoundException {
- //根據一個類的全名稱獲取類的類對象
- //如果類的全名稱錯誤或者不存在,則會報類查詢不到異常:ClassNotFoundException
- Class<?> clazz = Class.forName("java.lang.String");
- //獲取傳遞過來的類的所有方法
- Method[] methods = clazz.getDeclaredMethods();
- for (Method method : methods) {
- System.out.println(method.toString());
- }
- System.out.println("------------------------------我是分隔符:以下是類的屬性--------------------------------");
- //獲取傳遞過來的類的所有屬性
- Field[] fields = clazz.getDeclaredFields();
- for (Field field : fields) {
- System.out.println(field.toString());
- }
- System.out.println("------------------------------我是分隔符:以下是構造方法--------------------------------");
- //獲取傳遞過來的類的所有構造方法
- Constructor<?>[] constructor = clazz.getDeclaredConstructors();
- for (Constructor<?> ctt : constructor) {
- System.out.println(ctt.toString());
- }
- }
- }
創建對象
通過反射來生成對象的方式有兩種:
- 使用Class對象的newInstance()方法來創建該Class對象對應類的實例(這種方式要求該Class對象的對應類有默認構造器).
- 先使用Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance()方法來創建該Class對象對應類的實例(通過這種方式可以選擇指定的構造器來創建實例).
調用方法
當獲取到某個類對應的Class對象之後,就可以通過該Class對象的getMethod來獲取一個Method數組或Method對象.
每個Method對象對應一個方法,在獲得Method對象之後,就可以通過調用invoke方法來調用該Method對象對應的方法.
- package com.lwl.reflect;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- /**
- * 通過反射,對類中的方法進行操作
- * @create 2017-10-11 上午11:45:57
- * @version 1.0
- */
- public class ReflectMethodDemo {
- public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
- Class<?> clazz = Class.forName("com.lwl.reflect.Person");
- //獲取對象
- Object instance = clazz.newInstance();
- // instance = clazz.getDeclaredConstructor(null).newInstance(null);
- //如果已經知道方法的名稱,那麼調用起來更加方便
- Method method = clazz.getDeclaredMethod("setName", new Class[]{String.class});
- //設置值
- method.invoke(instance, new String[]{"jack"});
- System.out.println(instance.toString());
- //獲取值
- Method getMethod = clazz.getDeclaredMethod("getName", new Class[]{});
- Object getValue = getMethod.invoke(instance, new String[]{});
- System.out.println(getValue);
- //對對象中的靜態方法進行訪問
- Method staticMethod = clazz.getDeclaredMethod("printInfo", new Class[]{});
- //由於是靜態方法,所以這裏面的 instance 可以不傳,只用用 null 表示
- Object staticValue = staticMethod.invoke(instance, new String[]{});
- // staticValue = staticMethod.invoke(null, new String[]{});
- System.out.println(staticValue);
- }
- }
訪問成員變量
設置成員變量值.通過Class對象的的getField()方法可以獲取該類所包含的全部或指定的成員變量Field,Filed提供瞭如下兩組方法來讀取和
- getXxx(Object obj): 獲取obj對象的該成員變量的值, 此處的Xxx對應8中基本類型,如果該成員變量的類型是引用類型, 則取消get後面的Xxx;
- setXxx(Object obj, Xxx val): 將obj對象的該成員變量值設置成val值.此處的Xxx對應8種基本類型, 如果該成員類型是引用類型, 則取消set後面的Xxx;
- package com.lwl.reflect;
- import java.lang.reflect.Field;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- /**
- * 通過反射,對類中的字段進行操作
- * @create 2017-10-11 上午11:45:20
- * @version 1.0
- */
- public class ReflectFieldDemo {
- public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
- //獲取類對象
- Class<?> clazz = Class.forName("com.lwl.reflect.Person");
- //獲取對象
- Object instance = clazz.newInstance();
- // instance = clazz.getDeclaredConstructor(null).newInstance(null);
- //根據屬性的名稱 獲取屬性對象
- Field field = clazz.getDeclaredField("name");
- //獲取屬性的類型
- Class<?> type = field.getType();
- System.out.println(type); //out print class java.lang.String
- //獲取屬性的名稱
- String name = field.getName();
- System.out.println(name); //out print name
- //由於name屬性是private,如果不設置setAccessible是無法直接對其進行設置
- //setAccessible是暴力破壞,如果是私有方法同理要設置
- field.setAccessible(true);
- field.set(instance, "張三");
- System.out.println(instance.toString()); //out print Person [id=null, name=張三, address=null]
- }
- }
通過反射賦值
- package com.lwl.reflect;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- /**
- * 通過反射,對類對象進行賦值操作
- * @create 2017-10-11 上午11:44:58
- * @version 1.0
- */
- public class ReflectSetValueDemo {
- /**
- * 用一句話說明這個方法做什麼
- * @param args
- * @throws ClassNotFoundException
- * @throws SecurityException
- * @throws NoSuchFieldException
- * @throws NoSuchMethodException
- * @throws InvocationTargetException
- * @throws IllegalArgumentException
- * @throws IllegalAccessException
- * @throws InstantiationException
- * @create 2017-10-11 上午9:41:51
- */
- public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
- //獲取類的Class的三種方式
- /*
- * 1. Class.forName(類名稱全稱:包括包名)
- * 2. 類.class 即:Person.class
- * 3. 對象.getClass() new Person().getClass();
- * */
- Class<?> clazz = Class.forName("com.lwl.reflect.Person");
- // clazz = new Person().getClass();
- // clazz = Person.class;
- //獲取一個屬性
- Field field = clazz.getDeclaredField("address");
- System.out.println(field.toString());
- System.out.println("--------------------------------------------我是分隔符:以下是對方法進行操作--------------------------------------------------------");
- //獲取一個方法
- Method method = clazz.getDeclaredMethod("getName", new Class[]{});
- //傳遞的Class<?>的順序要和方法的參數類型順序保持一致,不然就無法匹配拋出異常:java.lang.NoSuchMethodException
- Method method1 = clazz.getDeclaredMethod("setName", String.class);
- //獲取方法的名字
- // String name = method1.getName();
- Method method2 = clazz.getDeclaredMethod("setInfo", String.class,Integer.class);
- //method1 與 method2 還可以使用另外一種方式獲取
- Method method3 = clazz.getDeclaredMethod("setName", new Class[]{String.class});
- Method method4 = clazz.getDeclaredMethod("setInfo", new Class[]{String.class,Integer.class});
- System.out.println(method.toString());
- System.out.println(method1.toString());
- System.out.println(method2.toString());
- System.out.println(method3.toString());
- System.out.println(method4.toString());
- System.out.println("--------------------------------------------我是分隔符:以下是對構造器進行操作--------------------------------------------------------");
- //因爲默認構造器沒有參數,使用可以傳入null 或者 new Class[]{}
- Constructor<?> cs = clazz.getDeclaredConstructor(new Class[]{});
- //帶參數的構造器
- Constructor<?> cs2 = clazz.getDeclaredConstructor(new Class[]{Integer.class,String.class,String.class});
- System.out.println(cs.toString());
- System.out.println(cs2.toString());
- System.out.println("--------------------------------------------我是分隔符:以下是對反射賦值進行操作--------------------------------------------------------");
- //根據類的默認構造器 創建一個類對象
- Object object = cs.newInstance(new Object[]{});
- // object = cs.newInstance(null);
- //根據類的帶參數構造器,創建一個類對象
- Object object2 = cs2.newInstance(new Object[]{1,"李四","南京"});
- // object2 = cs2.newInstance(null);
- System.out.println("原始的對象屬性情況:"+object);
- System.out.println("原始的對象屬性情況:"+object2);
- System.out.println("--------------------------------------------我是分隔符:以下是對反射賦值進行操作:設置開始--------------------------------------------------------");
- //對屬性進行設置值,先獲取所有的方法
- Method[] methods = clazz.getDeclaredMethods();
- //獲取類的所有屬性
- Field[] fields = clazz.getDeclaredFields();
- for (Method m : methods) {
- //獲取方法的名稱
- String name = m.getName();
- //如果名稱是以set開頭的,表示設置值
- if(name.startsWith("set")){
- //獲取set之後的字符串,即屬性的名稱
- String fieldName = name.substring(3);
- //因爲set之後的首個字符串是大寫,所以要截取第一個字符串轉化爲小寫,這裏千萬別把所有的字符串都轉化爲小寫,防止出現UserName 被轉化爲username
- fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
- //這裏會對類中的屬性進行賦值
- //由於Person裏面一個特殊的setInfo的方法,且info不是類的屬性,則不會進行賦值
- setFieldValue(fieldName, fields, m, object);
- }
- }
- System.out.println("賦值後的對象屬性情況:"+object);
- System.out.println("賦值後的對象屬性情況:"+object2);
- }
- /**
- * 給類屬性賦值
- * @param fieldName
- * @param fields
- * @param m
- * @param object
- * @throws IllegalAccessException
- * @throws IllegalArgumentException
- * @throws InvocationTargetException
- * @create 2017-10-11 上午10:41:53
- */
- public static void setFieldValue(String fieldName, Field[] fields, Method m, Object object) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
- for (Field field : fields) {
- if (field.getName().equals(fieldName)){
- //獲取字段的屬性
- Class<?> fieldClass = field.getType();
- //如果是Integer 即知道這個是Person的ID
- if(fieldClass == Integer.class){
- //通過反射設置值:也就是通過object對象,調用當前的 m 方法,後面是 m 方法需要的參數
- m.invoke(object, new Integer[]{1});
- }
- //因爲同爲String的有2個set方法,所有要通過屬性名稱判斷到底是調用哪個
- else if (fieldClass == String.class && "name".equals(fieldName)){
- //通過反射設置值:也就是通過object對象,調用當前的 m 方法,後面是 m 方法需要的參數
- m.invoke(object, new String[]{"jack"});
- }
- else if (fieldClass == String.class && "address".equals(fieldName)){
- //通過反射設置值:也就是通過object對象,調用當前的 m 方法,後面是 m 方法需要的參數
- m.invoke(object, new String[]{"南京"});
- }
- //不需要再次循環
- return;
- }
- }
- }
- }
使用到的輔助類:
- package com.lwl.reflect;
- public class Person {
- private Integer id;
- private String name;
- private String address;
- public Person() {
- }
- public Person(Integer id, String name, String address) {
- this.id = id;
- this.name = name;
- this.address = address;
- }
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- public void setInfo(String name,Integer id){
- this.id = id;
- this.name = name;
- }
- public static void printInfo(){
- System.out.println("我是靜態方法,我被調用了");
- }
- @Override
- public String toString() {
- return "Person [id=" + id + ", name=" + name + ", address=" + address
- + "]";
- }
- }