動態的創建Class對象方法及調用方式性能分析
有了Class對象,能做什麼?
-
創建類的對象:調用Class對象的newInstance()方法
-
類必須有一個無參數的構造器。
-
類的構造器的訪問許可權需要足夠。
思考?沒有無參的構造器就不能創建對象嗎?只要在操作的時候明確的調用類中的構造器,並將參數傳遞進去之後,才可以實例化操作。
-
如下
-
通過Class類的getDeclaredConstructor(Class … parameterTypes)取得本類的指定形參類型的構造器
-
向構造器的形參中傳遞一個對象數組進去,裡面包含了構造器中所需的各個參數
-
通過Constructor實例化對象
調用指定的方法
通過反射,調用類中的方法,通過Method類完成。
-
通過Class類的getMethod(String name,Class…parameterTypes)方法取得一個Method對象,並設置此方法操作時所需要的參數類型。
-
之後使用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語言訪問檢查。
-
提高反射的效率。如果程式碼中必須用反射,而該句程式碼需要頻繁的被調用,那麼請設置為true。
-
使得原本無法訪問的私有成員也可以訪問。
-
參數值為false則指示反射的對象應該實施Java語言訪問檢查。
package com.chao.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//動態的創建對象,通過反射
public class Test09 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//獲得Class對象
Class c1 = Class.forName("com.chao.reflection.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);
//invoke : 激活的意思
//(對象,"方法的值")
setName.invoke(user3,"追夢王子");
System.out.println(user3.getName());
//通過反射操作屬性
System.out.println("8888888888888888888888888888888888");
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有屬性,我們需要關閉程式的安全檢測,屬性或者方法的setAccessible(true).
name.setAccessible(true);
name.set(user4,"追夢王子2");
System.out.println(user4.getName());
}
}
調用方式的性能分析—-程式碼
package com.chao.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//分析性能問題
public class Test10 {
//普通方式調用
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("普通方式執行10億次:"+(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("反射方式執行10億次:"+(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("關閉檢測執行10億次:"+(endTime-startTime)+"ms");
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test01();
test02();
test03();
}
}