1. 程式人生 > 其它 >Java 註解和反射(五)建立執行時類的物件

Java 註解和反射(五)建立執行時類的物件

獲取執行時類的完整結構

通過反射獲取執行時類的完整結構

Field,Method,Constructor,Superclass,Interface,Annotation

~實現的全部介面

~所繼承的父類

~全部的構造器

~全部的方法

~全部的Field

~註解

............

//獲得類的資訊
public class Test07 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("refection.User");
        //獲得類的名字
        System.out.println(c1.getName());//包名+類名
        System.out.println(c1.getSimpleName());//類名

        //獲得類的屬性
        Field[] fields = c1.getFields();//只能找到public屬性的
        fields = c1.getDeclaredFields();//找到全部屬性
        for (Field field: fields) {
            System.out.println(field);
        }

        //獲得類的方法
        Method[] methods = c1.getMethods();//獲得本類及其父類的public所有方法
        methods = c1.getDeclaredMethods();//獲得本類的方法
        for (Method method: methods) {
            System.out.println(method);
        }

        //獲得指定構造器
        System.out.println("==============");
        Constructor[] constructors = c1.getConstructors();//獲得public
        constructors = c1.getDeclaredConstructors();//獲得全部
        for (Constructor constructor: constructors) {
            System.out.println(constructor);
        }
    }
}

動態建立物件

建立類的物件:呼叫Class物件的newInstance()方法

  1.類必須要有一個無引數構造器

  2.類的構造器的訪問許可權需要足夠

思考?==》難道沒有無參的構造器就不能建立物件了嗎?只要在操作的時候明確的呼叫類中的構造器,

     並將引數傳遞下去之後,才可以例項化操作

步驟如下:

    1.通過Class類的getDeclaredConstructor(Class.....parameterTypes)取得本類的指定形參型別的構造器

    2.向構造器的形參中傳遞一個物件陣列進去,裡面包含了構造器中所需的各個引數

    3.通過Constructor例項化物件

呼叫指定方法

通過反射,呼叫類中的方法,通過Method類完成

  1.通過Class類的getMethod(String name,Class....parameterTypes)方法取得一個Mehod物件並設定此方法操作時所需要的引數型別

  2.之後使用Object invoke(Object obj,Object[] args)進行呼叫,並向方法中傳遞要設定的obj物件的引數資訊

Object invoke(Object obj,Object[] args)

``Object對應原方法的返回值,若原方法無返回值,此時返回null

``若原方法若為靜態方法,此時形參Object obj可謂null

``若原方法形參列表為空,則Object[] args 為null

``若原方法宣告為private,則需要在呼叫此invoke()方法前,顯式呼叫方法物件的setAccessible(true)方法,將能訪問private方法

setAccessible

··Method和Field,Constructor物件都有setAccessible()方法

··setAccessible作用是啟動和禁用訪問安全檢查的開關

··引數值為true則指示反射的物件在使用時應該取消Java語言訪問檢查

  1.提高反射效率。如果程式碼中必須使用反射,而該句程式碼需要頻繁被呼叫,那麼請設定true

  2.使得原本無法訪問的私有成員也可訪問

··引數值為false則指示反射的物件應該實施Java語言訪問檢查

//動態建立物件,通過反射
public class Test08 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //獲得Class物件
        Class c1 = Class.forName("refection.User");
        //構造一個物件
        User user = (User) c1.newInstance();//本質呼叫無參構造器
        System.out.println(user);

        //通過構造器建立物件
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User user2 = (User) constructor.newInstance("嗚嗚", 001, 18);
        System.out.println(user2);

        //通過反射呼叫普通方法
        User user3 = (User) c1.newInstance();
        //通過反射獲取一個方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //啟用(物件,“方法值”)
        setName.invoke(user3,"小磊");
        System.out.println(user3.getName());

        //通過反射操作屬性
        User user4 = (User) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        //不能直接操作私有屬性,需要關閉程式安全檢測
        name.setAccessible(true);//設定true
        name.set(user4,"小朱");
        System.out.println(user4.getName());
    }
}

 其中的User類見Java註解和反射(三),根據需要刪除無參構造器

分析效能問題

//分析效能問題
public class Test09 {
    //普通方式呼叫
    public static void test01(){
        User user = new User();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("普通方式執行十億次="+(endTime-startTime)+"ms");
    }

    //反射方法呼叫
    public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方法執行十億次="+(endTime-startTime)+"ms");
    }
    //反射方式呼叫,關閉檢測
    public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
        getName.setAccessible(true);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方式呼叫,關閉檢測執行十億次="+(endTime-startTime)+"ms");
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test01();
        test02();
        test03();
    }
}

 

 其中的User類見Java註解和反射(三)