Java反射,从0开始
目錄
靜態(tài)VS動態(tài)語言
Java?Reflection(反射)介紹
Java反射機制提供的功能
Java反射優(yōu)點和缺點
反射相關(guān)的主要API
獲取運行時類的完整結(jié)構(gòu)
反射的使用
有了Class對象,如何創(chuàng)建對象?
使用反射調(diào)用對象的指定方法
Object invoke(Object obj, Object[] args)
setAccessible
性能檢測
反射操作泛型
反射操作注解
靜態(tài)VS動態(tài)語言
動態(tài)語言:
? ? 是一類在運行時可以改變其結(jié)構(gòu)的語言:例如新的函數(shù)、對象、甚至代碼可以被引進,已有的函數(shù)可以被刪除或是其他結(jié)構(gòu)上的變化。通俗短說就是在運行時代碼可以根據(jù)某些條件改變自身結(jié)構(gòu)。
? ? 主要動態(tài)語言:Object-C、C#、JavaScript、PHP、Python等。
靜態(tài)語言:
? ? 與動態(tài)語言相對應(yīng)的,運行時結(jié)構(gòu)不可變的語言就是靜態(tài)語言,如Java、C、C++。
? ? Java不是動態(tài)語言,但Java可以稱之為“準動態(tài)語言”。即Java有一定的動態(tài)性,我們可以利用反射機制獲得類似動態(tài)語言的特性。Java的動態(tài)性讓編程的時候更加靈活。
Java?Reflection(反射)介紹
? ? Reflection(反射)是Java被視為動態(tài)語言的關(guān)鍵,反射機制允許程序在執(zhí)行期借助于Reflection?API取得任何類的內(nèi)部信息,并能直接操作任意對象的內(nèi)部屬性及方法。
? ? Class?c =?Class.forName("java.lang.String")
? ? 加載完類之后,在堆內(nèi)存的方法區(qū)中就產(chǎn)生了一個Class類型的對象(一個類只有一個Class對象),這個對象就包含了完整的類的結(jié)構(gòu)信息。我們可以通過這個對象看到類的結(jié)構(gòu)。這個對象就像一面鏡子,透過這個鏡子看到類的結(jié)構(gòu),所以,我們形象的稱之為:反射。
Java反射機制提供的功能
? ? 在運行時判斷任意一個對象所屬的類。
? ? 在運行時構(gòu)造任意一個類的對象。
? ? 在運行時判斷任意一個類所具有的成員變量和方法。
? ? 在運行時獲取泛型信息。
? ? 在運行時調(diào)用任意一個對象的成員變量和方法。
? ? 在運行時處理注解。
? ? 生成動態(tài)代理。
? ? ......
Java反射優(yōu)點和缺點
? ? 優(yōu)點:可以實現(xiàn)動態(tài)創(chuàng)建對象和編譯,體現(xiàn)出很大的靈活性。
? ? 缺點:對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿足我們的要求。這類操作總是慢于直接執(zhí)行相同的操作。
反射相關(guān)的主要API
? ? java.lang.Class:代表一個類
? ? java.lang.reflect.Method:代表類的方法。
? ? java.lang.reflect.Field:代表類的成員變量。
? ? java.lang.reflect.Constructor:代表類的構(gòu)造器。
? ? ......
獲取運行時類的完整結(jié)構(gòu)
? ? 通過反射獲取運行時類的完整結(jié)構(gòu):Field、Method、Constructor、Superclass、Interface、Annotation。
? ? 實現(xiàn)的全部接口、所繼承的父類、全部的構(gòu)造器、全部的方法、全部的Field、注解等等。
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method;//獲取類的信息 public class Test06 {public static void main(String[] args) throws Exception {Class c1 = Class.forName("com.myUtils.reflectUtils.learn.MyUser");MyUser user = new MyUser();c1 = user.getClass();//獲得類的名字System.out.println(c1.getName());//包名 + 類名System.out.println(c1.getSimpleName());//獲得類名//獲得類的屬性Field[] fields = c1.getFields();//獲取所有(只能找到public的屬性)屬性fields = c1.getDeclaredFields();//獲取所有(找到全部的屬性)屬性Field id = c1.getDeclaredField("id");//獲取指定屬性//獲得類的方法Method[] methods = c1.getMethods();//獲取所有(本類及其父類public的)方法methods = c1.getDeclaredMethods();//獲取所有(本類全部的)方法Method getName = c1.getMethod("getName", null);Method setName = c1.getMethod("setName", String.class);//需要參數(shù)類型(重載問題)//獲得構(gòu)造器Constructor[] constructors = c1.getConstructors();Constructor constructor = c1.getConstructor(null);//也需要參數(shù)類型} }class MyUser{public Integer id;public String name;private int age;@Overridepublic String toString() {return "MyUser{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}';}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;}private int getAge() {return age;}public void setAge(int age) {this.age = age;} }反射的使用
有了Class對象,如何創(chuàng)建對象?
創(chuàng)建類的對象:調(diào)用Class對象的newInstance()方法:
? ? 1.類必須有一個無參數(shù)的構(gòu)造器。
? ? 2.類的構(gòu)造器的訪問權(quán)限需要足夠。
沒有無參構(gòu)造器、構(gòu)造器權(quán)限不足的情況創(chuàng)建對象:
? ? 1.通過Class類的getDeclaredConstructor(Class ... parameterTypes)取得本類的指定形參類型的構(gòu)造器。
? ? 2.向構(gòu)造器的形參中傳遞一個對象數(shù)組進去,里面包含了構(gòu)造器中所需的各個參數(shù)。
? ? 3.通過Constructor實例化對象。
使用反射調(diào)用對象的指定方法
通過反射,調(diào)用類中的方法,通過Method類完成。
? ? 1.通過Class類的getMethod(String name,Class ... parameterTypes)方法取得一個Method對象,并設(shè)置此方法操作時所需要的參數(shù)類型。
? ? 2.之后使用Object invoke(Object obj, Object[] args)進行調(diào)用,并向方法中傳遞要設(shè)置的obj對象的參數(shù)信息。
Object invoke(Object obj, Object[] args)
? ? Object對應(yīng)原方法的返回值,若原方法無返回值,此時返回null。
? ? 若原方法為靜態(tài)方法,此時形參Object?obj可為null。
? ? 若原方法形參列表為空,則Object[] args為null。
? ? 若原方法聲明為private,則需要在調(diào)用此invoke()方法前,顯式調(diào)用方法對象的setAccessible(true)方法。將可訪問private的方法。
setAccessible
? ? Method和Field、Construetor對象都有setAccessible()方法。
? ? setAccessible作用是啟動和禁用訪問安全檢查的開關(guān)。
? ? 參數(shù)值為true則指示反射的對象在使用時應(yīng)該取消Java語言訪問檢查。
?? ?? ? 提高反射的效率。如果代碼中必須用反射,而該句代碼需要頻繁的被調(diào)用,那么請設(shè)置為true;
?? ?? ? 使得原本無法訪問的私有成員也可以訪問。
? ? 參數(shù)值為false則指示反射的對象應(yīng)該實施Java語言訪問檢查。
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method;//通過反射創(chuàng)建對象 public class Test07 {public static void main(String[] args) throws Exception {Class c1 = Class.forName("com.myUtils.reflectUtils.learn.MyUser07");//構(gòu)造一個對象MyUser07 user = (MyUser07) c1.newInstance();//實際上調(diào)用了無參構(gòu)造器//通過構(gòu)造器創(chuàng)建對象Constructor constructor = c1.getDeclaredConstructor(Integer.TYPE, String.class);user = (MyUser07) constructor.newInstance(5, "張三");//通過反射調(diào)用方法Method setName = c1.getDeclaredMethod("setName", String.class);setName.invoke(user, "李四");//(對象,參數(shù))System.out.println(user.getName());//通過反射操作屬性Field name = c1.getDeclaredField("name");name.setAccessible(true);//設(shè)置為true就可以獲取到私有屬性、方法(關(guān)閉程序的安全監(jiān)測)name.set(user, "王五");System.out.println(name.get(user));} } class MyUser07{private Integer id;private String name;public MyUser07(Integer id, String name) {this.id = id;this.name = name;}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;} }?
性能檢測
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;public class Test08 {public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {/*** 普通時17ms* 反射耗時3398ms* 關(guān)閉檢測耗時1657ms*/test1();test2();test3();}//普通方式public static void test1(){User08 user08 = new User08();long startTime = System.currentTimeMillis();for (int i = 0; i < 1000000000; i++) {user08.getName();}long endTime = System.currentTimeMillis();System.out.println("普通時" + (endTime - startTime) + "ms");}//反射方式public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {User08 user08 = new User08();Class c1 = user08.getClass();Method getName = c1.getDeclaredMethod("getName", null);long startTime = System.currentTimeMillis();for (int i = 0; i < 1000000000; i++) {getName.invoke(user08, null);}long endTime = System.currentTimeMillis();System.out.println("反射耗時" + (endTime - startTime) + "ms");}//反射方式,關(guān)閉檢測public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {User08 user08 = new User08();Class c1 = user08.getClass();Method getName = c1.getDeclaredMethod("getName", null);getName.setAccessible(true);long startTime = System.currentTimeMillis();for (int i = 0; i < 1000000000; i++) {getName.invoke(user08, null);}long endTime = System.currentTimeMillis();System.out.println("關(guān)閉檢測耗時" + (endTime - startTime) + "ms");} } class User08{private Integer id;private String name;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;} }反射操作泛型
? ? Java采用泛型擦除的機制來引入泛型,Java的泛型僅僅是給編譯器javac使用的,確保數(shù)據(jù)的安全性和免去強制類型轉(zhuǎn)換問題,但是,一旦編譯完成,所有和泛型有關(guān)的類型全部擦除。
? ? 為了通過反射操作這些類型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType集中類型來代表不能被歸一到class類中的類型但是又和原始類型齊名的類型。
ParameterizedType:表示一種參數(shù)化類型,比如Collection<String>。
GenericArrayType:表示一種元素類型是參數(shù)化類型或者類型變量的數(shù)組類型。
TypeVariable:是各種類型變量的公共父接口。
WildcardType:代表一種通配符類型表達式。
import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map;//通過反射獲取泛型 public class Test09 {public void test01(Map<String, User> map, List<Integer> list){System.out.println("test01");}public Map<String, User> test02(){System.out.println("test02");return null;}public static void main(String[] args) throws NoSuchMethodException {//獲取方法參數(shù)泛型Method method = Test09.class.getMethod("test01", Map.class, List.class);Type[] genericParameterTypes = method.getGenericParameterTypes();for (Type genericParameterType : genericParameterTypes) {System.out.println("#"+genericParameterType);if(genericParameterType instanceof ParameterizedType){Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}}//獲取返回值泛型Method method2 = Test09.class.getMethod("test02", null);Type genericReturnType = method2.getGenericReturnType();//獲取返回類型System.out.println("#"+genericReturnType);if(genericReturnType instanceof ParameterizedType){Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();for (Type actualTypeArgument : actualTypeArguments) {System.out.println(actualTypeArgument);}}} }反射操作注解
import java.lang.annotation.*; import java.lang.reflect.Field;public class Test10 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {Class c1 = Class.forName("com.myUtils.reflectUtils.learn.Student10");//通過反射獲取注解Annotation[] annotations = c1.getAnnotations();for (Annotation annotation : annotations) {System.out.println(annotation);}//獲得注解的value的值TableTest tableTest = (TableTest)c1.getAnnotation(TableTest.class);String value = tableTest.value();System.out.println(value);//db_student//獲得類指定的注解Field f = c1.getField("name");FieldTest annotation = f.getAnnotation(FieldTest.class);System.out.println(annotation.columnName());System.out.println(annotation.type());System.out.println(annotation.length());} }@TableTest("db_student") class Student10{@FieldTest(columnName = "db_id", type = "int", length = 10)private Integer id;@FieldTest(columnName = "db_name", type = "varchar", length = 20)private String name;public Student10() {}public Student10(Integer id, String name) {this.id = id;this.name = name;}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;} }//類名的注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface TableTest{String value(); } //屬性的注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface FieldTest{String columnName();String type();int length(); }?
總結(jié)
以上是生活随笔為你收集整理的Java反射,从0开始的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 还在对java类、类的加载一知半解?这篇
- 下一篇: java对象创建的流程到底是什么样子的?