一.反射之實例化Class類的5種方式:
java的數據類型可以分為兩類,即引用類型和原始類型(即基本數據類型)。
對於每種類型的對象,java虛擬機會實例化不可變的java.lang.Class對象。
它提供了在運行時檢查對象屬性的方法,這些屬性包括它的成員和類型信息。
更重要的是Class對象是所有反射API的入口。
Class類是泛型類,可以使用@SuppressWarnings("unchecked")忽略泛型或者使用Class<V>類型。
獲得Class對象的5種方式:
1."Object.getClass()" : 如果一個類的對象可用,則最簡單的獲得Class的方法是使用Object.getClass()。
當然,此方式只對引用類型有效。2. ".class"------------- : 如果類型可用但沒有對象,則可以在類型后加上".class"來獲得Class對象。這也是使原始類型
獲得Class對象最簡單的方式:
3."Class.forName()"---: 如果知道類的全名,則可以使用靜態方法Class.forName()來獲得Class對象,它不能用在原始類型上,但是可以用在原始類型數組上。(注:此方式會拋出ClassNotFoundException異常)
4. "包裝類的TYPE域"-----: 每一個原始類型和void都有包裝類。利用其TYPE域就可以獲得Class對象。
5."以Class為返回值的方法": 如獲取內部類的getDeclaredClasses()方法,此時返回一個對象數組
--支持知識共享,轉載請標注地址"http://www.cnblogs.com/XHJT/p/3915221.html "——和佑博客園,謝謝~~--
代碼實例:
package com.xhj.reflection_excetion; /** * 反射之實例化Class類的5種方式 * * @author XIEHEJUN * */ public class InstantiateClassObject { @SuppressWarnings("rawtypes") public static void main(String[] args) throws ClassNotFoundException { System.out.print("第一種方式--用Object.getClass()方法獲取到的String類的對象為: "); Class class1 = new String().getClass(); System.out.println(class1.getName()); System.out.print("第二種方式--用.class()方法獲取到的String類的對象為: "); class1 = String.class; System.out.println(class1.getName()); System.out.print("第三種方式--用.forName()方法獲取到的String類的對象為: "); class1 = Class.forName("java.lang.String"); System.out.println(class1.getName()); System.out.print("第四種方式--用包裝類的TYPE域獲取到的Integer類的對象為: "); class1 = Integer.TYPE; System.out.println(class1.getName()); System.out.println("第五種方式--用getDeclaredClasses()獲取String類的內部類對象:"); Class<?>[] clazz = new String().getClass().getDeclaredClasses(); for (Class<?> class2 : clazz) { System.out.println("\t"+class2); } } }
結果為:
注:除了java.lang.reflect.ReflectPermission和java.lang.reflect包外,所有類都沒有公共的
構造方法。為了獲得這些類的對象,必須使用Class類中適當的方法,對於不同的數據類型,Class
對象的獲得方式是不同。
二.反射之查看類的定義:
通常類的聲明包括常見修飾符(public,protected,private,abstract,static,final,strictfp等)、
類的名稱、類的泛型參數、類的繼承類(實現的接口)、類的注解等信息。
Class類的實例表示正在運行的Java應用程序中的類和接口:
枚舉是一種類,注釋是一種接口。
每一個數組屬於被映射為Class對象的一個類,所有具有相同元素類型和維數的數組都共享該Class對象;
基本數據類型和關鍵字void也表示為Class對象。
Class沒有公共的構造方法。
Class對象是在加載類時由Java虛擬機以及通過調用類加載器中的defineClass方法自動構造的。
Class類常用方法:
forName(String className)-: 根據給定的名稱獲得Class對象
getAnnotations()------------: 返回此Class對象上存在的注釋
getCanonicalName() --------: 返回Java Language Specification 中所定義的底層類的規范化名稱
getGenericInterfaces()------: 返回泛型形式的對象類所實現的接口
getGenericSuperclass() -----: 返回泛型形式的對象類所直接繼承的超類
getModifuers() --------------: 返回此類或接口以整數編碼的Java語言修飾符
getTypeParameters() -------: 按聲明順序返回TypeVariable對象的一個數組
注:Java語言預定義的注解只有@Deprecated可以在運行時獲得。
實例代碼:
package com.xhj.reflection_excetion; import java.lang.annotation.Annotation; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; /** * 查看類的定義 * * @author XIEHEJUN * */ public class CheckClassStatement { public static void main(String[] args) throws ClassNotFoundException { Class<?> classtest = Class.forName("java.util.ArrayList"); System.out.println("1.根據給定的名稱獲得Class對象:" + classtest.getName()); Annotation[] annotations = classtest.getAnnotations(); System.out.print("2.獲取此對象上的注解為:"); if (annotations.length > 0) { for (Annotation annotation : annotations) { System.out.println(annotation + "\t"); } } else { System.out.println("空"); } System.out.println("3.獲得Java語言規范化名稱:" + classtest.getCanonicalName()); System.out.println("4.獲取類上的修飾符:共有" + classtest.getModifiers() + "個,為: " + Modifier.toString(classtest.getModifiers())); TypeVariable<?>[] typeV = classtest.getTypeParameters(); System.out.print("5.在對象上獲取到的泛型是:"); if (typeV.length > 0) { for (TypeVariable<?> typeVariable : typeV) { System.out.println(typeVariable); } } else { System.out.println("空"); } System.out.println("6.在對象上獲取到的接口為:"); // 使用getInterfaces()不包含泛型;使用getGenericInterfaces包含泛型 Type[] intefaces = classtest.getGenericInterfaces(); if (intefaces.length > 0) { for (Type type : intefaces) { System.out.println("\t" + type); } } else { System.out.println("空"); } Class class2 = classtest.getSuperclass(); System.out.print("7.在對象上獲取直接繼承類:"); if (class2 != null) { System.out.println(class2); } else { System.out.println("空"); } } }
結果為:
注:getSuperclass()方法也不能獲得有泛型信息的父類
三.反射之獲得Class對象表示實體的名稱
對於不同類型的對象,其Class對象的名稱是不同的,反過來說就是從這個名稱就可以知道該對象的類型。
注:
1.如果此類對象表示的是非數組類型的引用類型,則返回該類的二進制名稱。
2.如果此類對象表示一個基本類型或者void,則返回其對應的Java語言的關鍵字的字符串。
3.如果此類對象表示一個數組類,名字的內部形式為"[元素編碼",其深度為幾維,就有幾個"["。
其元素類型編碼為:
——————————————————————————————————————————————————
元素類型 編 碼
boolean Z
byte B
char C
short S
int I
float F
double D
long J
class or interfaces Lclassname(即當元素是引用類型或者接口的時候,編碼為"L+類名")
____________________________________________________
實例代碼:
package com.xhj.reflection_excetion; /** * 獲取對象實體的名稱 * * @author XIEHEJUN * */ public class GetClassEntityName { /** * 數組元素類型編碼為: * 元素類型 編碼 * boolean Z * byte B * char C * short S * int I * float F * double D * long J * class or interfaces Lclassname(即當元素是引用類型或者接口的時候,編碼為"L+類名") */ public static void main(String[] args) { System.out.println("獲取非數組類型的引用類型,返回該類的二進制名稱: " + new String().getClass().getName()); System.out.println("獲取基本類型,返回其對應的Java語言的關鍵字的字符串: " + int.class.getName()); System.out.println("獲取void類型,返回其對應的Java語言的關鍵字的字符串: " + void.class.getName()); System.out.println("獲取一維數組類型的基本類型,返回'[+元素編碼': " + new int[2].getClass().getName()); System.out.println("獲取一維數組類型的引用類型,返回'[+元素編碼': " + new String[2].getClass().getName()); System.out.println("獲取二維數組類型的基本類型,返回'[+元素編碼': " + new int[2][3].getClass().getName()); System.out.println("獲取二維數組類型的引用類型,返回'[+元素編碼': " + new String[2][3].getClass().getName()); System.out.println("用getCanonicalName()獲取二維數組類型的基本類型,返回數組名稱" + new int[2][3].getClass().getCanonicalName()); System.out.println("用getCanonicalName()獲取二維數組類型的引用類型,返回數組名稱" + new String[2][3].getClass().getCanonicalName()); } }
結果為:
注:
對於數組來說,用getCanonicalName()方法可以獲取的到數組的名稱,且比較容易接受和辨認
四.反射之查看類的成員
我們要查看類的定義,首先想到的當然是API文檔,但若是找不到API文檔又該如何呢?此時就要用到Java的反射機制了。
另外我們在無法查看源代碼的情況下,也可以通過反射機制查看類的成員,包括"域,構造方法,普通方法和內部類"等。
主要用到的方法:
getConstructors() -------: 返回由該類對象的所有構造方法組成的數組
getDeclaredFields() -----: 返回由該類對象的所有非繼承域組成的數組
getDeclaredMethods() -- : 返回由該類對象的所有非繼承方法組成的數組
getFields() -------------- : 返回由該類對象的所有公共域組成的數組
getMethod() -------------: 返回由該類對象的所有公共方法組成的數組
代碼實例:
package com.xhj.reflection_excetion; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 查看類的成員 * * @author XIEHEJUN * */ public class CheckClassMembers { public static void main(String[] args) { Class<?> strclass = new String().getClass(); // 查看構造方法 System.out.println(strclass.getName() + "的構造方法有:"); Constructor<?>[] constructors = strclass.getConstructors(); if (constructors.length > 0) { for (Constructor<?> constructor : constructors) { System.out.println("\t" + constructor); } } else { System.out.println("空"); } // 查看非繼承域 System.out.println(strclass.getName() + "的非繼承域有:"); Field[] declaredFields = strclass.getDeclaredFields(); if (declaredFields.length > 0) { for (Field field : declaredFields) { System.out.println("\t" + field); } } else { System.out.println("空"); } // 查看非繼承方法 System.out.println(strclass.getName() + "的非繼承方法有:"); Method[] declaredMethods = strclass.getDeclaredMethods(); if (declaredMethods.length > 0) { for (Method method : declaredMethods) { System.out.println("\t" + method); } } else { System.out.println("空"); } // 查看所有公共域 System.out.println(strclass.getName() + "的所有域有:"); Field[] fields = strclass.getFields(); if (fields.length > 0) { for (Field field : fields) { System.out.println("\t" + field); } } else { System.out.println("空"); } // 查看所有公共的方法 System.out.println(strclass.getName() + "的所有繼承方法有:"); Method[] methods = strclass.getMethods(); if (methods.length > 0) { for (Method method : methods) { System.out.println("\t" + method); } } else { System.out.println("空"); } } }
結果為:
(打印出來的數據太多,這里之展示部分結果~)
注:對於私有域或方法,如果有安全管理器,可能會報異常。
五:反射之查看內部類消息
Class類的getDeclaredClasses()方法返回Class對象的一個數組,這些對象反映聲明為該Class對象
所表示的類的成員的所有類和接口,包括該類所聲明的公共、保護、默認(包)訪問及私有類和接口,
但不包括繼承的類和接口。若該類不將任何類或接口聲明為成員,或者該對象表示基本類型、數組類或
void,則該方法返回一個長度為0的數組。
public Class<?> [] getDeclaredClasses() throws SecurityException
注:利用Class類的getDeclaredClasses()方法可以獲得一個數組,其中的每一個成員代表一個內部類的類對象。
然后我們可以像獲取普通類的信息一樣,獲取到內部類的信息。
代碼實例:
package com.xhj.reflection_excetion; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 查看內部類的消息 * * @author XIEHEJUN * */ public class CheckInnerClass { public static void main(String[] args) { Class<?> clazz = new String().getClass(); Class[] class1 = clazz.getDeclaredClasses(); for (int i = 0; i < class1.length; i++) { Class<?> innerclass = class1[i]; System.out .println("================================================================"); System.out.println("內部類" + i + "為: " + innerclass.getName()); System.out.println("內部類" + i + "的父類為:" + innerclass.getSuperclass().getName()); System.out.print("內部類" + i + "的所有公共域為:"); Field[] field = innerclass.getFields(); if (field.length > 0) { System.out.println(); for (Field field2 : field) { System.out.println("\t" + field2); } } else { System.out.println("空"); } System.out.print("內部類" + i + "的非繼承域為:"); Field[] declaredfield = innerclass.getDeclaredFields(); if (declaredfield.length > 0) { System.out.println(); for (Field field2 : declaredfield) { System.out.println("\t" + field2); } } else { System.out.println("空"); } System.out.print("內部類" + i + "的所有公共方法為:"); Method[] methods = innerclass.getMethods(); if (methods.length > 0) { System.out.println(); for (Method method : methods) { System.out.println("\t" + method); } } else { System.out.println("空"); } System.out.print("內部類" + i + "的非繼承方法為:"); Method[] declaredmethods = innerclass.getDeclaredMethods(); if (declaredmethods.length > 0) { System.out.println(); for (Method method : declaredmethods) { System.out.println("\t" + method); } } else { System.out.println("空"); } } } }
結果為:
(打印出來的數據太多,這里之展示部分結果~)
六.反射之按繼承層次對類排序
Java提供了instanceof運算符來比較兩個類(或接口)之間是否存在繼承關系。
但是對於多個類來說,這種方法是很麻煩的。這時候,我們要做的應該是利用
java的反射機制來對存在繼承關系的類進行排序。
主要方法:
TreeSet<E> 是基於TreeMap的NavigableSet實現的。它使用元素的自然順序對
元素進行排序,或者根據創建set時提供的Comparator進行排序,具體取決於
使用的構造方法。本節采用Class類中的isAssignableFrom()方法來判斷當前
Class 對象所表示的類與給定的Class對象所表示的類之間的關系,若相同或
是父類則返回true,否則返回false。
public boolean isAssignableFrom(Class<?> clazz)
注:Java中與排序相關的接口有Comparable和Comparator。這兩個接口通過對象之
間比較的結果--一個有符號的整數來比較對象的大小。實現任何一個接口都可
以讓對象具有排序的能力。固可以用TreeSet也可以用Arrays.sort()來進行排序。
代碼實例:
package com.xhj.reflection_excetion; import java.awt.Container; import java.util.Comparator; import java.util.TreeSet; import javax.swing.JComponent; import javax.swing.JPanel; /** * 比較並將類按繼承關系排序 * * @author XIEHEJUN * */ public class CompareClasses implements Comparator<Class<?>> { @Override public int compare(Class<?> o1, Class<?> o2) { if (o1.equals(o2)) { return 0; } else if (o1.isAssignableFrom(o2)) { return -1; } else if (o2.isAssignableFrom(o1)) { return 1; } else { throw new IllegalArgumentException(o1+"和"+o2+"兩個類之間沒有聯系"); } } public static void main(String[] args) { TreeSet<Class<?>> treeSet = new TreeSet<Class<?>>( new CompareClasses()); System.out.println("添加類——JComponent.class"); treeSet.add(JComponent.class); System.out .println("添加類——Container.class"); treeSet.add(Container.class); System.out.println("添加類——JPanel.class"); treeSet.add(JPanel.class); System.out.println("=================排序后為====================="); for (Class<?> class1 : treeSet) { System.out.println(class1); } } }
結果為: