反射
類加載
類在記憶體中的生命周期:加載-->使用-->解除安裝
當程式主動使用某個類時,如果該類還未被加載到記憶體中,系統會通過加載、連接配接、初始化三個步驟來對該類進行初始化
類的加載又分為三個階段:
(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表示
調用任意類型的方法
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、調用注解對象的配置參數的方法擷取配置參數值
擷取屬性上的注解:
2、擷取某個屬性Field對象
3、調用getAnnot ation()方法得到注解對象
4、調用注解對象的配置參數的方法擷取配置參數值
擷取方法上的注解:
2、擷取某個方法method對象
擷取内部類或外部類資訊
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)方法。】
AccessibleObject
此類為下面3個類的基類
// 将此對象的 accessible 标志設定為訓示的布爾值
//即強制将私有的屬性、方法、構造器設定為可通路
void setAccessible(boolean flag)
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
将此 Method 與指定對象進行比較 | |
以 String 形式傳回此 Method 對象表示的方法名稱 | |
Object invoke(Object obj, Object... args) | 對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法 |
Class<?> getReturnType() | 傳回一個 Class 對象,該對象描述了此 Method 對象所表示的方法的正式傳回類型 |
Class<?>[] getParameterTypes() | 按照聲明順序傳回 Class 對象的數組,這些對象描述了此 Method 對象所表示的方法的形參類型 |
以整數形式傳回此 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
将此 Constructor 對象與指定的對象進行比較 | |
以字元串形式傳回此構造方法的名稱 | |
Class<T> getDeclaringClass() | 傳回 Class 對象,該對象表示聲明由此 Constructor 對象表示的構造方法的類 |
以整數形式傳回此 Constructor 對象所表示構造方法的 Java 語言修飾符 | |
T newInstance(Object... initargs) | 使用此 Constructor 對象表示的構造方法來建立該構造方法的聲明類的新執行個體,并用指定的初始化參數初始化該執行個體 |
按照聲明順序傳回一組 Class 對象,這些對象表示此 Constructor 對象所表示構造方法的形參類型 | |
按照聲明順序傳回一組 Type 對象,這些對象表示此 Constructor 對象所表示的方法的形參類型 |