程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 深刻懂得Java反射

深刻懂得Java反射

編輯:關於JAVA

深刻懂得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反射,願望對年夜家有所贊助,假如年夜家有任何疑問請給我留言,小編會實時答復年夜家的。在此也異常感激年夜家對網站的支撐!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved