Java進階之反射__Java

來源:互聯網
上載者:User
1反射的基石Class類 1.Java類用於描述一類事物的共性,該類事物有什麼屬性,沒有什麼屬性,至於這個屬性的值是什麼,則是由這個類的執行個體對象來確定的,不同的執行個體對象有不同的屬性值。Java程式中的各個Java類,它們是否屬於同一類事物,是不是可以用一個類來描述這類事物呢。這個類的名字就是Class,要注意與小寫class關鍵字的區別哦。Class類描述了哪些方面的資訊呢。類的名字,類的訪問屬性,類所屬於的包名,欄位名稱的列表、方法名稱的列表,等等。學習反射,首先就要明白Class這個類。寫如下代碼進行對比理解:
/*Person p1 = new Person("zhangsan");
Person p2 = new Person("lisi");
*/
/*Class x1 = Vector類在記憶體裡的位元組碼
Class x2 = Date類在記憶體裡的位元組碼*/
Class x1 = Vector.class;
Class x2 = Date.class;

每個java類都是Class的一個執行個體對象,它們的內容不同,但是,它們的特徵相同,譬如,都有方法,有欄位,有父類,有包。
2. ******講課時要一定畫一張圖:多個類的位元組碼裝載入記憶體,在記憶體中加入一個個方塊空間表示位元組碼,然後用一個個橢圓表示以這個位元組碼建立出來的執行個體對象,並用監視代碼來說明位元組碼只被裝載一次,而它構造的執行個體對象的構造方法被調用了多次。用如下代碼更進一步說明Class的執行個體是什麼。是一份位元組碼,一個類在虛擬機器中通常只有一份位元組碼:
Date d1 = new Date();
Class clazz1 = d1.getClass();
Class clazz2 = Date.class;
Class clazz3 = null;
clazz3 = Class.forName("java.util.Date");

if(clazz1==clazz2)
{
System.out.println(clazz1.getName());
}
if(clazz1==clazz3)
{
System.out.println(clazz1.getName());
}
3.一個奇怪的問題:載入了位元組碼,並調用了其getMethods之類的方法,但是沒有看到類的靜態代碼塊被執行,只有在第一個執行個體對象被建立時,這個靜態代碼才會被執行。準確的說,靜態代碼塊不是在類載入時被調用的,而是第一個執行個體對象被建立時才執行的。




反射的基石--Class類

對比提問: Person類代表人,它的執行個體對象就是張三,李四這樣一個個具體的人, Java程式中的各個Java類屬於同一類事物,描述這類事物的Java類名就是Class。對比提問:眾多的人用一個什麼類表示。眾多的Java類用一個什麼類表示。
人--Person
Java類--Class

Class類代表Java類,它的各個執行個體對象又分別對應什麼呢。
對應各個類在記憶體中的位元組碼,例如,Person類的位元組碼,ArrayList類的位元組碼,等等。
一個類被類載入器載入到記憶體中,佔用一片儲存空間,這個空間裡面的內容就是類的位元組碼,不同的類的位元組碼是不同的,所以它們在記憶體中的內容是不同的,這一個個的空間可分別用一個個的對象來表示,這些對象顯然具有相同的類型,這個類型是什麼呢。

如何得到各個位元組碼對應的執行個體對象( Class類型)
類名.class,例如,System.class
對象.getClass(),例如,new Date().getClass()
Class.forName("類名"),例如,Class.forName("java.util.Date");

九個預定義Class執行個體對象:
參看Class.isPrimitive方法的協助
Int.class == Integer.TYPE

數群組類型的Class執行個體對象
Class.isArray()
總之,只要是在來源程式中出現的類型,都有各自的Class執行個體對象,例如,int[],void…

Demo: view plain copy to clipboard print ? package cn.itcast;      import java.util.Date;      /**  * 測試三個位元組碼是否為同一個位元組碼  * @author partner4java  *  */   public class ReflectTest1 {       public static void main(String[] args) throws ClassNotFoundException {           Date date = new Date();           Class date1 = date.getClass();           Class date2 = Class.forName("java.util.Date");           System.out.println("date1 == date2 ?" + (date1 == date2));                      Class date3 = Date.class;           System.out.println("date1 == date3 ?" + (date1 == date3));              //      後台列印:   //      date1 == date2 ?true   //      date1 == date3 ?true          }      }  




Class JDK文檔:

public final class Class<T>extends Objectimplements Serializable, GenericDeclaration, Type, AnnotatedElementClass 類的執行個體表示正在啟動並執行 Java 應用程式中的類和介面。枚舉是一種類,注釋是一種介面。每個數組屬於被映射為 Class 對象的一個類,所有具有相同元素類型和維數的數組都共用該 Class 對象。基本的 Java 類型(boolean、byte、char、short、int、long、float 和 double)和關鍵字 void 也表示為 Class 對象。 

Class 沒有公用構造方法。Class 對象是在載入類時由 JAVA 虛擬機器以及通過調用類載入器中的 defineClass 方法自動構造的。 

以下樣本使用 Class 對象來顯示對象的類名: 


void printClassName(Object obj) {
System.out.println("The class of " + obj +
" is " + obj.getClass().getName());
}
還可以使用一個類字面值(JLS Section 15.8.2)來獲得命名類型(或 void)的 Class 對象。例如: 


System.out.println("The name of class Foo is: "+Foo.class.getName());



方法摘要 
<U> Class<? extends U> 
asSubclass(Class<U> clazz) 
強制轉換該 Class 對象,以表示指定的 class 對象所表示的類的一個子類。 
T cast(Object obj) 
將一個對象強制轉換成此 Class 對象所表示的類或介面。 
boolean desiredAssertionStatus() 
如果要在調用此方法時,將要初始化該類,則返回將分配給該類的斷言狀態。 
static Class<?> forName(String className) 
返回與帶有給定字串名的類或介面相關聯的 Class 對象。 
static Class<?> forName(String name, boolean initialize, ClassLoader loader) 
使用給定的類載入器,返回與帶有給定字串名的類或介面相關聯的 Class 對象。 
<A extends Annotation> 

getAnnotation(Class<A> annotationClass) 
如果存在該元素的指定類型的注釋,則返回這些注釋,否則返回 null。 
Annotation[] getAnnotations() 
返回此元素上存在的所有注釋。 
String getCanonicalName() 
返回《Java Language Specification》中所定義的基礎類的正常化名稱。 
Class[] getClasses() 
返回一個包含某些 Class 對象的數組,這些對象表示屬於此 Class 對象所表示的類的成員的所有公用類和介面,包括從超類和公用類繼承的以及通過該類聲明的公用類和介面成員。 
ClassLoader getClassLoader() 
返回該類的類載入器。 
Class<?> getComponentType() 
返回表示數組組件類型的 Class。 
Constructor<T> getConstructor(Class... parameterTypes) 
返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公用構造方法。 
Constructor[] getConstructors() 
返回一個包含某些 Constructor 對象的數組,這些對象反映此 Class 對象所表示的類的所有公用構造方法。 
Annotation[] getDeclaredAnnotations() 
返回直接存在於此元素上的所有注釋。 
Class[] getDeclaredClasses() 
返回 Class 對象的一個數組,這些對象反映聲明為此 Class 對象所表示的類的成員的所有類和介面,包括該類所聲明的公用、保護、預設(包)訪問及私人類和介面,但不包括繼承的類和介面。 
Constructor<T> getDeclaredConstructor(Class... parameterTypes) 
返回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或介面的指定構造方法。 
Constructor[] getDeclaredConstructors() 
返回 Constructor 對象的一個數組,這些對象反映此 Class 對象表示的類聲明的所有構造方法。 
Field getDeclaredField(String name) 
返回一個 Field 對象,該對象反映此 Class 對象所表示的類或介面的指定已聲明欄位。 
Field[] getDeclaredFields() 
返回 Field 對象的一個數組,這些對象反映此 Class 對象所表示的類或介面所聲明的所有欄位,包括公用、保護、預設(包)訪問和私人欄位,但不包括繼承的欄位。 
Method getDeclaredMethod(String name, Class... parameterTypes) 
返回一個 Method 對象,該對象反映此 Class 對象所表示的類或介面的指定已聲明方法。 
Method[] getDeclaredMethods() 
返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或介面聲明的所有方法,包括公用、保護、預設(包)訪問和私人方法,但不包括繼承的方法。 
Class<?> getDeclaringClass() 
如果此 Class 對象所表示的類或介面是另一個類的成員,則返回的 Class 對象表示該對象的聲明類。 
Class<?> getEnclosingClass() 
返回基礎類的立即封閉類。 
Constructor<?> getEnclosingConstructor() 
如果該 Class 對象表示構造方法中的一個本地或匿名類,則返回 Constructor 對象,它表示基礎類的立即封閉構造方法。 
Method getEnclosingMethod() 
如果此 Class 對象表示某一方法中的一個本地或匿名類,則返回 Method 對象,它表示基礎類的立即封閉方法。 
T[] getEnumConstants() 
如果此 Class 對象不表示枚舉類型,則返回枚舉類的元素或 null。 
Field getField(String name) 
返回一個 Field 對象,它反映此 Class 對象所表示的類或介面的指定公用成員欄位。 
Field[] getFields() 
返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或介面的所有可訪問公用欄位。 
Type[] getGenericInterfaces() 
返回表示某些介面的 Type,這些介面由此對象所表示的類或介面直接實現。 
Type getGenericSuperclass() 
返回表示此 Class 所表示的實體(類、介面、基本類型或 void)的直接超類的 Type。 
Class[] getInterfaces() 
確定此對象所表示的類或介面實現的介面。 
Method getMethod(String name, Class... parameterTypes) 
返回一個 Method 對象,它反映此 Class 對象所表示的類或介面的指定公用成員方法。 
Method[] getMethods() 
返回一個包含某些 Method 對象的數組,這些對象反映此 Class 對象所表示的類或介面(包括那些由該類或介面聲明的以及從超類和超介面繼承的那些的類或介面)的公用 member 方法。 
int getModifiers() 
返回此類或介面以整數編碼的 Java 語言修飾符。 
String getName() 
以 String 的形式返回此 Class 對象所表示的實體(類、介面、數組類、基本類型或 void)名稱。 
Package getPackage() 
擷取此類的包。 
ProtectionDomain getProtectionDomain() 
返回該類的 ProtectionDomain。 
URL getResource(String name) 
尋找帶有給定名稱的資源。 
InputStream getResourceAsStream(String name) 
尋找具有給定名稱的資源。 
Object[] getSigners() 
擷取此類的標記。 
String getSimpleName() 
返回原始碼中給出的基礎類的簡稱。 
Class<? super T> getSuperclass() 
返回表示此 Class 所表示的實體(類、介面、基本類型或 void)的超類的 Class。 
TypeVariable<Class<T>>[] getTypeParameters() 
按聲明順序返回 TypeVariable 對象的一個數組,這些對象表示用此 GenericDeclaration 對象所表示的常規聲明來聲明的類型變數。 
boolean isAnnotation() 
如果此 Class 對象表示一個注釋類型則返回 true。 
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 
如果指定類型的注釋存在於此元素上,則返回 true,否則返回 false。 
boolean isAnonymousClass() 
若且唯若基礎類是匿名類時返回 true。 
boolean isArray() 
判定此 Class 對象是否表示一個數組類。 
boolean isAssignableFrom(Class<?> cls) 
判定此 Class 對象所表示的類或介面與指定的 Class 參數所表示的類或介面是否相同,或是否是其超類或超介面。 
boolean isEnum() 
若且唯若該類聲明為原始碼中的枚舉時返回 true。 
boolean isInstance(Object obj) 
判定指定的 Object 是否與此 Class 所表示的對象賦值相容。 
boolean isInterface() 
判定指定的 Class 對象是否表示一個介面。 
boolean isLocalClass() 
若且唯若基礎類是本地類時返回 true。 
boolean isMemberClass() 
若且唯若基礎類是成員類時返回 true。 
boolean isPrimitive() 
判定指定的 Class 對象是否表示一個基本類型。 
boolean isSynthetic() 
如果此類是複合類,則返回 true,否則 false。 
T newInstance() 
建立此 Class 對象所表示的類的一個新執行個體。 
String toString() 
將對象轉換為字串。 



2反射

反射就是把Java類中的各種成分映射成相應的java類。例如,一個Java類中用一個Class類的對象來表示,一個類中的組成部分:成員變數,方法,構造方法,包等等資訊也用一個個的Java類來表示,就像汽車是一個類,汽車中的發動機,變速箱等等也是一個個的類。表示java類的Class類顯然要提供一系列的方法,來獲得其中的變數,方法,構造方法,修飾符,包等資訊,這些資訊就是用相應類的執行個體對象來表示,它們是Field、Method、Contructor、Package等等。 
一個類中的每個成員都可以用相應的反射API類的一個執行個體對象來表示,通過調用Class類的方法可以得到這些執行個體對象後,得到這些執行個體對象後有什麼用呢。怎麼用呢。這正是學習和應用反射的要點。



3Constructor類
Constructor類代表某個類中的一個構造方法

得到某個類所有的構造方法:
例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();

得到某一個構造方法:
例子: Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
//獲得方法時要用到類型

建立執行個體對象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc"));
//調用獲得的方法時要用到上面相同類型的執行個體對象

Class.newInstance()方法:
例子:String obj = (String)Class.forName("java.lang.String").newInstance();
該方法內部先得到預設的構造方法,然後用該構造方法建立執行個體對象。
該方法內部的具體代碼是怎樣寫的呢。用到了緩衝機制來儲存預設構造方法的執行個體對象。





Constructor<T> JDK文檔:
public final class Constructor<T>extends AccessibleObjectimplements GenericDeclaration, MemberConstructor 提供關於類的單個構造方法的資訊以及對它的存取權限。 

Constructor 允許在將實參與帶有基礎構造方法的形參的 newInstance() 匹配時進行擴充轉換,但是如果發生收縮轉換,則拋出 IllegalArgumentException。 

方法摘要 
boolean equals(Object obj) 
將此 Constructor 對象與指定的對象進行比較。 
<T extends Annotation> 

getAnnotation(Class<T> annotationClass) 
如果存在該元素的指定類型的注釋,則返回這些注釋,否則返回 null。 
Annotation[] getDeclaredAnnotations() 
返回直接存在於此元素上的所有注釋。 
Class<T> getDeclaringClass() 
返回 Class 對象,該對象表示聲明由此 Constructor 對象表示的構造方法的類。 
Class<?>[] getExceptionTypes() 
返回一組表示聲明要拋出的異常類型的 Class 對象,這些異常是由此 Constructor 對象表示的基礎構造方法拋出的。 
Type[] getGenericExceptionTypes() 
返回一組 Type 對象,這些對象表示聲明要由此 Constructor 對象拋出的異常。 
Type[] getGenericParameterTypes() 
按照聲明順序返回一組 Type 對象,這些對象表示此 Constructor 對象所表示的方法的形參類型。 
int getModifiers() 
以整數形式返回此 Constructor 對象所表示構造方法的 Java 語言修飾符。 
String getName() 
以字串形式返回此構造方法的名稱。 
Annotation[][] getParameterAnnotations() 
按照聲明順序返回一組數組,這些數組表示通過此 Method 對象表示的方法的形參上的注釋。 
Class<?>[] getParameterTypes() 
按照聲明順序返回一組 Class 對象,這些對象表示此 Constructor 對象所表示構造方法的形參類型。 
TypeVariable<Constructor<T>>[] getTypeParameters() 
按照聲明順序返回一組 TypeVariable 對象,這些對象表示通過此 GenericDeclaration 對象所表示的一般聲明來聲明的類型變數。 
int hashCode() 
返回此 Constructor 的雜湊碼。 
boolean isSynthetic() 
如果此構造方法是一個複合構造方法,則返回 true;否則返回 false。 
boolean isVarArgs() 
如果聲明此構造方法可以帶可變數量的參數,則返回 true;否則返回 false。 
T newInstance(Object... initargs) 
使用此 Constructor 對象表示的構造方法來建立該構造方法的聲明類的新執行個體,並用指定的初始化參數初始化該執行個體。 
String toGenericString() 
返回描述此 Constructor 的字串,其中包括型別參數。 
String toString() 
返回描述此 Constructor 的字串。 





4Field類
view plain copy to clipboard print ? Field類代表某個類中的一個成員變數      ReflectPoint point = new ReflectPoint(1,7);   Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");   System.out.println(y.get(point));   //Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");   Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");   x.setAccessible(true);  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.