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註解和反射(三)