深刻懂得Java反射。本站提示廣大學習愛好者:(深刻懂得Java反射)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻懂得Java反射正文
要想懂得反射的道理,起首要懂得甚麼是類型信息。Java讓我們在運轉時辨認對象和類的信息,重要有2種方法:一種是傳統的RTTI,它假定我們在編譯時曾經曉得了一切的類型信息;另外一種是反射機制,它許可我們在運轉時發明和應用類的信息。
1、Class對象
懂得RTTI在Java中的任務道理,起首須要曉得類型信息在運轉時是若何表現的,這是由Class對象來完成的,它包括了與類有關的信息。Class對象就是用來創立一切“慣例”對象的,Java應用Class對象來履行RTTI,即便你正在履行的是相似類型轉換如許的操作。
每一個類都邑發生一個對應的Class對象,也就是保留在.class文件。一切類都是在對其第一次應用時,靜態加載到JVM的,當法式創立一個對類的靜態成員的援用時,就會加載這個類。Class對象僅在須要的時刻才會加載,static初始化是在類加載時停止的。
public class TestMain { public static void main(String[] args) { System.out.println(XYZ.name); } } class XYZ { public static String name = "luoxn28"; static { System.out.println("xyz靜態塊"); } public XYZ() { System.out.println("xyz結構了"); } }
輸入成果為:
類加載器起首會檢討這個類的Class對象能否已被加載過,假如還沒有加載,默許的類加載器就會依據類名查找對應的.class文件。
想在運轉時應用類型信息,必需獲得對象(好比類Base對象)的Class對象的援用,應用功效Class.forName(“Base”)可以完成該目標,或許應用base.class。留意,有一點很風趣,應用功效”.class”來創立Class對象的援用時,不會主動初始化該Class對象,應用forName()會主動初始化該Class對象。為了應用類而做的預備任務普通有以下3個步調:
•加載:由類加載器完成,找到對應的字節碼,創立一個Class對象
•鏈接:驗證類中的字節碼,為靜態域分派空間
•初始化:假如該類有超類,則對其初始化,履行靜態初始化器和靜態初始化塊
public class Base { static int num = 1; static { System.out.println("Base " + num); } } public class Main { public static void main(String[] args) { // 不會初始化靜態塊 Class clazz1 = Base.class; System.out.println("------"); // 會初始化 Class clazz2 = Class.forName("zzz.Base"); } }
2、類型轉換前先做檢討
編譯器將檢討類型向下轉型能否正當,假如不正當將拋出異常。向下轉換類型前,可使用instanceof斷定。
class Base { } class Derived extends Base { } public class Main { public static void main(String[] args) { Base base = new Derived(); if (base instanceof Derived) { // 這裡可以向下轉換了 System.out.println("ok"); } else { System.out.println("not ok"); } } }
3、反射:運轉時類信息
假如不曉得某個對象切實其實切類型,RTTI可以告知你,然則有一個條件:這個類型在編譯時必需已知,如許能力應用RTTI來辨認它。Class類與java.lang.reflect類庫一路對反射停止了支撐,該類庫包括Field、Method和Constructor類,這些類的對象由JVM在啟動時創立,用以表現未知類裡對應的成員。如許的話便可以應用Contructor創立新的對象,用get()和set()辦法獲得和修正類中與Field對象聯系關系的字段,用invoke()辦法挪用與Method對象聯系關系的辦法。別的,還可以挪用getFields()、getMethods()和getConstructors()等很多方便的辦法,以前往表現字段、辦法、和結構器對象的數組,如許,對象信息可以在運轉時被完整肯定上去,而在編譯時不須要曉得關於類的任何工作。
反射機制並沒有甚麼奇異的地方,當經由過程反射與一個未知類型的對象打交道時,JVM只是簡略地檢討這個對象,看它屬於哪一個特定的類。是以,誰人類的.class關於JVM來講必需是可獲得的,要末在當地機械上,要末從收集獲得。所以關於RTTI和反射之間的真正差別只在於:
•RTTI,編譯器在編譯時翻開和檢討.class文件
•反射,運轉時翻開和檢討.class文件
public class Person implements Serializable { private String name; private int age; // get/set辦法 } public static void main(String[] args) { Person person = new Person("luoxn28", 23); Class clazz = person.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { String key = field.getName(); PropertyDescriptor descriptor = new PropertyDescriptor(key, clazz); Method method = descriptor.getReadMethod(); Object value = method.invoke(person); System.out.println(key + ":" + value); } }
以上經由過程getReadMethod()辦法挪用類的get函數,可以經由過程getWriteMethod()辦法來挪用類的set辦法。平日來講,我們不須要應用反射對象,然則它們在創立靜態代碼會更有效,反射在Java頂用來支撐其他特征的,例如對象的序列化和JavaBean等。
4、靜態署理
署理形式是為了供給額定或分歧的操作,而拔出的用來替換”現實”對象的對象,這些操作觸及到與”現實”對象的通訊,是以署理平日充任中央人腳色。Java的靜態署理比署理的思惟更進步了一步,它可以靜態地創立並署理並靜態地處置對所署理辦法的挪用。在靜態署理上所做的一切挪用都邑被重定向到單一的挪用處置器上,它的任務是提醒挪用的類型並肯定響應的戰略。以下是一個靜態署理示例:
接口和完成類:
public interface Interface { void doSomething(); void somethingElse(String arg); } public class RealObject implements Interface { public void doSomething() { System.out.println("doSomething."); } public void somethingElse(String arg) { System.out.println("somethingElse " + arg); } }
靜態署理對象處置器:
public class DynamicProxyHandler implements InvocationHandler { private Object proxyed; public DynamicProxyHandler(Object proxyed) { this.proxyed = proxyed; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { System.out.println("署理任務了."); return method.invoke(proxyed, args); } }
測試類:
public class Main { public static void main(String[] args) { RealObject real = new RealObject(); Interface proxy = (Interface) Proxy.newProxyInstance( Interface.class.getClassLoader(), new Class[] {Interface.class}, new DynamicProxyHandler(real)); proxy.doSomething(); proxy.somethingElse("luoxn28"); } }
輸入成果以下:
經由過程挪用Proxy靜態辦法Proxy.newProxyInstance()可以創立靜態署理,這個辦法須要獲得一個類加載器,一個你願望該署理完成的接口列表(不是類或籠統類),和InvocationHandler的一個完成類。靜態署理可以將一切挪用重定向到挪用處置器,是以平日會挪用處置器的結構器傳遞一個”現實”對象的援用,從而將挪用處置器在履行中介義務時,將要求轉發。
以上所述是小編給年夜家引見的深刻懂得Java反射,願望對年夜家有所贊助,假如年夜家有任何疑問請給我留言,小編會實時答復年夜家的。在此也異常感激年夜家對網站的支撐!