動態編程(一):反射

一、反射機制

1.1概念

在運行狀態中,對於任意一個實體類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲java語言的反射機制。

主要提供了以下功能:

  • 在運行時判斷任意一個對象所屬的類。
  • 在運行時構造任意一個類的對象。
  • 在運行時判斷任意一個類所具有的成員變量和方法。
  • 在運行時調用任意一個對象的方法

1.2應用場合

反射的重點在於運行時階段,可以動態加載和獲取。常見的應用場合:

  • 訪問沒有權限的方法或屬性
  • 編碼階段不能確定需要創建的類
  • 處理註解
  • 動態代理

1.3特點

優點:
提升程序的靈活性和擴展性
缺點:
破壞代碼的封裝性和可讀性
性能差。反射相當於一系列解釋操作,通知jvm要做的事情,性能比直接的java代碼要慢很多。

二、API

2.1常用類

java.lang.Class; //類               
java.lang.reflect.Constructor;//構造方法 
java.lang.reflect.Field; //類的成員變量       
java.lang.reflect.Method;//類的方法
java.lang.reflect.Modifier;//訪問權限

2.2獲取Class對象

/**
 * 方式一:調用某個對象的getClass()方法
 */
User p=new User();
Class clazz=user.getClass();
/**
 * 方式二:調用某個類的class屬性來獲取該類對應的Class對象
 */
Class clazz=User.class;
/**
 * 使用反射:使用Class類中的forName()靜態方法;
 */
Class clazz=Class.forName("com.lin.app.test.User");

2.3 Class API

//是否是基礎類型
boolean isPrimitive = class1.isPrimitive();
//是否是集合類
boolean isArray = class1.isArray();
//是否是註解類
boolean isAnnotation = class1.isAnnotation();
//是否是接口類
boolean isInterface = class1.isInterface();
//是否是枚舉類
boolean isEnum = class1.isEnum();
//是否是匿名內部類
boolean isAnonymousClass = class1.isAnonymousClass();
//是否被某個註解類修飾
boolean isAnnotationPresent = class1.isAnnotationPresent(Deprecated.class);
//獲取class名字 包含包名路徑
String className = class1.getName();
//獲取class的包信息
Package aPackage = class1.getPackage();
//獲取class類名
String simpleName = class1.getSimpleName();
//獲取class訪問權限
int modifiers = class1.getModifiers();
//內部類
Class<?>[] declaredClasses = class1.getDeclaredClasses();
//外部類
Class<?> declaringClass = class1.getDeclaringClass();

2.4創建類實例

        /**
         * 方式一:使用默認構造函數創建
         * 調用Class.newInstance()
         * 或通過Constructor.newInstance
         */
        try {
            Class clazz = User.class;
            User user = (User) clazz.newInstance();
            Constructor constructor = clazz.getConstructor();
            User user1 = (User) constructor.newInstance();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        /**
         * 方式二:使用帶參構造函數創建
         * 調用Constructor.newInstance
         */
        try {
            Class clazz = User.class;
            Constructor constructor = clazz.getDeclaredConstructor(String.class, String.class);
            User user = (User) constructor.newInstance("", "");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

2.5方法和字段相關API

常用Field API
            /**
             * Class:
             * Field getField(String name)      獲得類聲明的指定公共字段(無法獲取Private字段)
             * Field[] getFields()              獲得類聲明的所有公共字段(無法獲取Private字段)
             * Field getDeclaredField(String name)  獲取類聲明的指定字段
             * Field[] getDeclaredFields()          獲取類聲明的所有字段
             *
             * Field:
             * getType()            返回這個變量的類型
             * getGenericType()     如果當前屬性有簽名屬性類型就返回,否則就返回 Field.getType()
             * isEnumConstant()     判斷這個屬性是否是枚舉類
             * getModifiers()       獲取語言修飾符 public、private等
             * getName()            獲取屬性的名字
             * get(Object obj)      獲取該對象屬性值
             * set(Object obj, Object value) 設置該對象屬性值
             * setAccessible(boolean flag)   設置允許訪問private對象
             */
常用Method API
            /**
             * Class:
             * getMethods();                                        獲取類聲明的公共方法(無法獲取Private方法)
             * getMethod(String name, Class<?>... parameterTypes)   獲取類聲明的指定公共方法(無法獲取Private方法)
             * getDeclaredMethods();                                獲取類聲明的所有方法
             * getDeclaredMethod(String name, Class<?>... parameterTypes) 獲取類聲明的指定方法
             *
             * Method:
             * getDeclaringClass()              返回方法所在的Class
             * getParameterTypes()              形參類型
             * getExceptionTypes()              拋出的異常類型
             * getReturnType()                  返回類型
             * getModifiers()       獲取語言修飾符 public、private等
             * getName()            獲取方法名稱
             * setAccessible(boolean flag)      設置允許訪問private對象
             * isBridge()                       是否是橋接方法
             * isSynthetic()                    是否是複合方法
             * isVarArgs()                      是否帶有可變參數
             * invoke(Object obj, Object... args)調用方法
             * getAnnotation(Class<T> annotationClass) 獲取註解信息
             */

三、示例

public class Test {
    public void getClazz() {
        //方式一:使用默認構造函數創建
        try {
            Class clazz = User.class;
            User user = (User) clazz.newInstance();
            Constructor constructor = clazz.getConstructor();
            User user1 = (User) constructor.newInstance();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        //方式二:通過Constructor.newInstance創建
        try {
            Class clazz = User.class;
            Constructor constructor = clazz.getDeclaredConstructor(String.class, String.class);
            User user = (User) constructor.newInstance("", "");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        try {
            Class clazz = Class.forName("com.lin.app.test.User");
            Object obj = clazz.getDeclaredConstructor(String.class, String.class).newInstance("姓名", "地址");
            Field address = clazz.getDeclaredField("address");
            //設置允許訪問private對象
            address.setAccessible(true);
            //獲取address的值
            print("before ", address.getName(), address.get(obj).toString());
            //改變address的值
            address.set(obj, "成都");
            print("after ", address.getName(), address.get(obj).toString());

            Method setMethod=clazz.getDeclaredMethod("setName",String.class);
            //設置允許訪問private對象
            setMethod.setAccessible(true);
            Method getMethod=clazz.getDeclaredMethod("getName",String.class);
            getMethod.setAccessible(true);
            print("before",getMethod.getName(),((String)getMethod.invoke(obj)));
            setMethod.invoke(obj,"張三");
            print("after",getMethod.getName(),((String)getMethod.invoke(obj)));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private void print(String... msg) {
        StringBuilder builder = new StringBuilder();
        for (String s : msg) {
            builder.append(s).append(" - ");
        }
        if (builder.length() > 0) {
            builder.deleteCharAt(builder.length() - 2);
        }
        Log.e(getClass().getSimpleName(), builder.toString());
    }
}

public class User {
    private String name;
    private String address;

    public User() {
    }

    public User(String name, String address) {
        this.name = name;
        this.address = address;
    }

    private String getName() {
        return name;
    }

    private void setName(String name) {
        this.name = name;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章