Java語法進階15-反射

反射

類加載

類在內存中的生命週期:加載-->使用-->卸載

當程序主動使用某個類時,如果該類還未被加載到內存中,系統會通過加載、連接、初始化三個步驟來對該類進行初始化

類的加載又分爲三個階段:

(1)加載:load

就是指將類型的class字節碼數據讀入內存

(2)連接:link

  ①驗證:校驗合法性等

  ②準備:準備對應的內存(方法區),創建Class對象,爲類變量賦默認值,爲靜態常量賦初始值。

  ③解析:把字節碼中的符號引用替換爲對應的直接地址引用

(3)初始化:initialize(類初始化)即執行<clinit>類初始化方法,大多數情況下,類的加載就完成了類的初始化,有些情況下,會延遲類的初始化。

類初始化

1、哪些操作會導致類的初始化?

(1)運行主方法所在的類,要先完成類初始化,再執行main方法

(2)第一次使用某個類型就是在new它的對象,此時這個類沒有初始化的話,先完成類初始化再做實例初始化

(3)調用某個類的靜態成員(類變量和類方法),此時這個類沒有初始化的話,先完成類初始化

(4)子類初始化時,發現它的父類還沒有初始化的話,那麼先初始化父類

(5)通過反射操作某個類時,如果這個類沒有初始化,也會導致該類先初始化

2、哪些使用類的操作,但是不會導致類的初始化?

(1)使用某個類的靜態的常量(static final)

(2)通過子類調用父類的靜態變量,靜態方法,只會導致父類初始化,不會導致子類初始化。

(3)用某個類型聲明數組並創建數組對象時,不會導致這個類初始化

類加載器

(1)引導類加載器(Bootstrap Classloader)又稱爲根類加載器

   它負責加載jre/rt.jar核心庫,它本身不是Java代碼實現的,也不是ClassLoader的子類,獲取它的對象時往往返回null

(2)擴展類加載器(Extension ClassLoader)

  它負責加載jre/lib/ext擴展庫,它是ClassLoader的子類

(3)應用程序類加載器(Application Classloader)

    它負責加載項目的classpath路徑下的類,它是ClassLoader的子類

(4)自定義類加載器

  當你的程序需要加載“特定”目錄下的類,可以自定義類加載器;

加載器的雙親委託模式

 下一級的類加載器,如果接到任務時,會先搜索是否加載過,如果沒有,會先把任務往上傳,如果都沒有加載過,一直到根加載器,如果根加載器在它負責的路徑下沒有找到,會往回傳,如果一路回傳到最後一級都沒有找到,那麼會報ClassNotFoundException或NoClassDefError

 類加載器之間不是繼承關係,是組合的方式實現的。

Class

 Java反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;

簡單理解爲JVM運行時會在方法區記錄所有class文件中所有類的信息(類名,屬性,方法),並將所有類又做爲Class類的對象。當調用某個類時就會將其先加載到內存中,

也就是將這個類作爲Class類的對象被創建出來。在Class類中定義了許多供操作(此類)的方法(創建對象,調用屬性和方法),從而可以動態的修改程序結構

Class對象是反射的根源,所有Java類型都可以獲取它的類型對象。

Class 類的對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的 defineClass方法自動構造,在方法區創建的,不是由程序員創建的,Class 沒有公共構造方法。

獲取Class對象的四種方式

(1)類型名.class

要求編譯期間已知類型

(2)對象.getClass()

獲取對象的運行時類型

(3)Class.forName(類型全名稱)

可以獲取編譯期間未知的類型

(4)ClassLoader的類加載器對象.loadClass(類型全名稱)

可以用系統類加載對象或自定義加載器對象加載指定路徑下的類型

獲取類型的詳細信息

可以獲取:包、修飾符、類型名、父類(包括泛型父類)、父接口(包括泛型父接口)、成員(屬性、構造器、方法)、註解(類上的、方法上的、屬性上的)

public ClassLoader getClassLoader() 【返回該類的類加載器】
public String toString() 【將對象轉換爲字符串】
public Package getPackage() 【獲取此類的包】
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或接口的指定構造方法
public Constructor<?>[] getDeclaredConstructors() throws SecurityException 【返回此 Class 對象表示的類聲明的所有構造方法】
public native int getModifiers();

【 返回此類或接口以整數編碼的 Java 語言修飾符,用二進制的某一位1,來代表一種修飾符】

public String getName()

【以 String 的形式返回此 Class 對象所表示的實體(類、接口、數組類、基本類型或 void)名稱】

public native Class<? super T> getSuperclass();

【返回表示此 Class 所表示的實體(類、接口、基本類型或 void)的超類的 Class】

public Type getGenericSuperclass()

【返回此 Class 所表示的實體(類、接口、基本類型或 void)

直接超類的 Type】

public Class<?>[] getInterfaces() 【確定此對象所表示的類或接口實現的接口】
public Field getField(String name) 【返回此 Class 對象所表示的類或接口的指定公共成員字段】
public Field[] getFields() throws SecurityException 【返回此 Class 對象所表示的類或接口的所有可訪問公共字段】
public Field getDeclaredField(String name) 【返回此 Class 對象所表示的類或接口的指定已聲明字段】
public Field[] getDeclaredFields() throws SecurityException 【返回此 Class 對象所表示的類或接口所聲明的所有字段】
public Method getMethod(String name, Class<?>... parameterTypes) 【返回此 Class 對象所表示的類或接口的指定公共成員方法】
public Method[] getMethods() throws SecurityException

【返回此 Class 對象所表示的類或接口(包括那些由該類或接口

聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法】

public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 【返回此 Class 對象所表示的類或接口的指定已聲明方法】
public Method[] getDeclaredMethods() throws SecurityException

【此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法】

public T newInstance() 【創建此 Class 對象所表示的類的一個新實例】
public Annotation[] getAnnotations() 【返回此元素上存在的所有註釋】
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) 【如果存在該元素的指定類型的註釋,則返回這些註釋,否則返回 null】
public T[] getEnumConstants() 【如果此 Class 對象不表示枚舉類型,則返回枚舉類的元素或 null】
public boolean isMemberClass() 【當且僅當底層類是成員類時返回 true】
public native boolean isInterface(); 【判定指定的 Class 對象是否表示一個接口類型】

創建任意引用類型的對象

1、直接通過Class對象來實例化(要求必須有無參構造)

  • (1)獲取該類型的Class對象(2)創建對象 newInstance()

2、通過獲取構造器對象來進行實例化

  • (1)獲取該類型的Class對象(2)獲取構造器對象(3)創建對象 newInstance(Object... initargs)

如果構造器的權限修飾符修飾的範圍不可見,也可以調用setAccessible(true)

操作任意類型的屬性

(1)獲取該類型的Class對象

Class clazz = Class.forName("com.guigu.bean.User");

(2)獲取屬性對象

Field field = clazz.getDeclaredField("username");

(3)設置屬性可訪問

field.setAccessible(true);

(4)創建實例對象:如果操作的是非靜態屬性,需要創建實例對象

Object obj = clazz.newInstance();

(4)設置屬性值

field.set(obj,"chai");

(5)獲取屬性值 Object value = field.get(obj);

如果操作靜態屬性變量,那麼實例對象可以省略,用null表示

調用任意類型的方法

(1)獲取該類型的Class對象

Class clazz = Class.forName("com.atguigu.service.UserService");

(2)獲取方法對象

Method method = clazz.getDeclaredMethod("login",String.class,String.class);

(3)創建實例對象

Object obj = clazz.newInstance();

(4)調用方法

Object result = method.invoke(obj,"chai","123);

如果方法的權限修飾符修飾的範圍不可見,也可以調用setAccessible(true)

如果方法是靜態方法,實例對象也可以省略,用null代替

獲取泛型父類

1、獲取子類的Class對象

2、調用getGenericSuperClass()獲取泛型父類

3、強轉爲ParameterizedType類型

4、調用getActualTypeArguments()獲取實際類型參數

讀取註解信息

獲取上的註解:

1、獲取Class對象

2、調用getAnnotation()方法得到註解對象

3、調用註解對象的配置參數的方法獲取配置參數值

獲取屬性上的註解:

1、獲取Class對象

2、獲取某個屬性Field對象

3、調用getAnnot ation()方法得到註解對象

4、調用註解對象的配置參數的方法獲取配置參數值

獲取方法上的註解:

1、獲取Class對象

2、獲取某個方法method對象

3、調用getAnnot ation()方法得到註解對象

4、調用註解對象的配置參數的方法獲取配置參數值

獲取內部類或外部類信息

public Class<?>[] getClasses():  

【返回所有公共內部類和內部接口。包括從超類繼承的公共類和接口成員以及該類聲明的公共類和接口成員。】

public Class<?>[] getDeclaredClasses():

【返回 Class 對象的一個數組,這些對象反映聲明爲此 Class 對象所表示的類的成員的所有類和接口。包括該類所聲明的公共、保護、默認(包)訪問及私有類和接口,但不包括繼承的類和接口】 

public Class<?> getDeclaringClass(): 

【如果此 Class 對象所表示的類或接口是一個內部類或內部接口,則返回它的外部類或外部接口,否則返回null。】 

動態創建和操作任意類型的數組

java.lang.reflect包下還提供了一個Array類,Array對象可以代表所有的數組。程序可以通過使用Array類來動態的創建數組,操作數組元素等。

Array類提供瞭如下幾個方法:

public static Object newInstance(Class<?> componentType, int... dimensions):

【創建一個具有指定的組件類型和維度的新數組。】

public static void setXxx(Object array,int index,xxx value):

【將array數組中[index]元素的值修改爲value。此處的Xxx對應8種基本數據類型,如果該屬性的類型是引用數據類型,則直接使用set(Object array,int index, Object value)方法。】

public static xxx getXxx(Object array,int index,xxx value):

【將array數組中[index]元素的值返回。此處的Xxx對應8種基本數據類型,如果該屬性的類型是引用數據類型,則直接使用get(Object array,int index)方法。】

Field

String getName() 返回此 Field 對象表示的字段的名稱
Object get(Object obj) 返回指定對象上此 Field 表示的字段的值
int getModifiers() 以整數形式返回由此 Field 對象表示的字段的 Java 語言修飾符
boolean equals(Object obj) 將此 Field 與指定對象比較
Type getGenericType() 返回一個 Type 對象,它表示此 Field 對象所表示字段的聲明類型
boolean getBoolean(Object obj) 獲取一個靜態或實例 boolean 字段的值
int getInt(Object obj) 獲取 int 類型或另一個通過擴展轉換可以轉換爲 int 類型的基本類型的靜態或實例字段的值
void set(Object obj, Object value) 將指定對象變量上此 Field 對象表示的字段設置爲指定的新值
void setShort(Object obj, short s) 將字段的值設置爲指定對象上的一個 short 值
void setInt(Object obj, int i) 將字段的值設置爲指定對象上的一個 int 值

Method

boolean equals(Object obj) 將此 Method 與指定對象進行比較
String getName() 以 String 形式返回此 Method 對象表示的方法名稱
Object invoke(Object obj, Object... args) 對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法
Class<?> getReturnType() 返回一個 Class 對象,該對象描述了此 Method 對象所表示的方法的正式返回類型
Class<?>[] getParameterTypes() 按照聲明順序返回 Class 對象的數組,這些對象描述了此 Method 對象所表示的方法的形參類型
int getModifiers() 以整數形式返回此 Method 對象所表示方法的 Java 語言修飾符
Type getGenericReturnType() 返回表示由此 Method 對象所表示方法的正式返回類型的 Type 對象
Type[] getGenericParameterTypes() 返回一個 Type對象的數組, Type以聲明順序表示由該對象表示的可執行文件的形式參數類型
Type[] getGenericExceptionTypes() 返回一個 Type對象的數組, Type此可執行對象聲明拋出的異常
Class<?>[] getExceptionTypes() 返回 Class 對象的數組,這些對象描述了聲明將此 Method 對象表示的底層方法拋出的異常類型
Class<?> getDeclaringClass() 返回表示聲明由此 Method 對象表示的方法的類或接口的 Class 對象
Annotation[] getDeclaredAnnotations() 返回直接存在於此元素上的所有註釋

Constructor

boolean equals(Object obj) 將此 Constructor 對象與指定的對象進行比較
String getName() 以字符串形式返回此構造方法的名稱
Class<T> getDeclaringClass() 返回 Class 對象,該對象表示聲明由此 Constructor 對象表示的構造方法的類
int getModifiers() 以整數形式返回此 Constructor 對象所表示構造方法的 Java 語言修飾符
T newInstance(Object... initargs) 使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例
Class<?>[] getParameterTypes() 按照聲明順序返回一組 Class 對象,這些對象表示此 Constructor 對象所表示構造方法的形參類型
Type[] getGenericParameterTypes() 按照聲明順序返回一組 Type 對象,這些對象表示此 Constructor 對象所表示的方法的形參類型
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章