Java反射框架(一)——介紹、Class類
目錄
1.介紹
1.1使用反射
反射提供了檢測調節執行在jvm上的應用的執行時行為的能力
反射是非常強力的功能並且可以令應用執行不可能的操作。
反射的常見應用:
- 反射機制允許應用可以使用外部的使用者自定義的類,即利用它們的完整限定名稱建立擴充套件物件。
- 反射機制可以用於構建類瀏覽器實現列舉類成員。
- 型別資訊可以通過反射獲得,一次幫助開發者編寫正確程式碼。
- 反射可以檢查類的私有成員。
- 反射可以系統地呼叫定義在類中的可發現的API集合。
1.2反射的缺點
反射框架十分強力,但是不能隨意使用。
如果不適用反射框架就能達成操作,那最好就不要使用反射。
效能開銷
由於反射涉及動態解析型別,一些jvm的優化不會執行。
安全限制
反射框架需要執行時許可權,但有些SecurityManager不會授權。
內部暴露
反射可以執行非反射程式碼的非法功能,例如,方位private域與方法。
這樣破壞了封裝性,將可能產生程式碼行為混亂以及破壞移植性。
反射破壞了抽象性,所以,當平臺升級時,程式碼行為可能發生改變。
2.Class
對每一種型別的物件,JVM都例項化一個java.lang.Class的不可變例項。
Class提供了檢測物件執行時屬性(即物件的成員與方法)的方法。
Class提供了建立新類與物件的能力。
Class類是Reflection框架的進入點。
2.1遍歷類物件
所有反射操作的進入點都是java.lang.Class。
除了ReflectPermission類,其餘java.lang.reflect中的類都不具有public構造器。
可以通過物件、類名稱、型別、存在的Class來獲取Class物件。
Object.getClass()
Class c = "fff".getClass();
note:獲取String物件"fff"的Class物件。
ps:只有繼承Object的物件,才能以這種方式獲取Class。
ps:對介面物件使用getClass,獲取實現類物件。
語法.class
Class c = boolean.class;
note:獲取boolean的Class。
Class c = int[][][].class;
note:獲取多維陣列的Class。
Class.forName()
Class c = Class.forName("examples.Foo");
note:通過完整類名examples.Foo獲取Foo的Class類。
ps:靜態方法Class.forName()通過使用完整類名獲取對應的Class。
如果Class表示的是陣列,陣列型別名稱的內部形式需要在元素型別名稱之前放置一個或多個'['用以表示巢狀陣列的深度。
Class c = Class.forName("[[[[I");
note:等價於int[][][][].class。
原始型別包裝者的TYPE域
wrapper將原始型別包裝為引用型別。
Class c = Double.TYPE;
Class c = Void.TYPE;
note:第一個Class與doubel.class等價,第二個Class與void.class等價。
返回Class物件的方法
可以通過反射框架APIs提供的一些方法返回Class物件。
Class.getSuperclass()
Class c = javax.swing.JButton.class.getSuperclass();
note:獲取javax.swing.JButton的父類的Class。
Class.getClasses()
Class<?>[] c = Character.class.getClasses();
note:獲取Character內定義的所有的類與介面(即public內部類與介面)的Class,包括繼承的內部類與介面。
Class.getDeclaringClasses()
獲取內部定義的類與介面(不一定是public)的Class,匿名內部類不算,繼承的內部類也不算。
Class.getDeclaringClass()
如果給定Class是內部類或介面,返回定義了它的類的Class物件,如果不是內部類或介面,返回null。
java.lang.reflect.Field.getDeclaringClass():獲取聲明瞭此域的類的Class物件。
java.lang.reflect.Method.getDeclaringClass()
java.lang.reflect.Constructor.getDeclaringClass()
Class.getEnclosingClass()
獲取封閉類的Class物件,可以用於獲取匿名內部類的封閉類。
2.2檢測類修飾符與型別
java.lang.reflect.Modifier包含了所有可能的修飾符的宣告。
Modifier用於解析Class.getModifiers()返回的修飾符集合。
獲取類名稱
c.getCanonicalName();
note:獲取Class物件c表示的類的名稱。
獲取修飾符
Modifier.toString(c.getModifiers());
note:獲取Class物件c表示的類的所有修飾符。
ps:所有介面都會被jvm設定為abstract。
獲取型別引數名
TypeVariable[] tv = c.getTypeParameters();
note:獲取Class物件c表示的類定義的型別引數名。
獲取實現的介面
Type[] intfs = c.getGenericInterfaces();
note:獲取Class物件c表示的類實現的所有介面。
獲取持有的註解
Annotation[] ann = c.getAnnotations();
note:獲取Class物件c表示的類持有的所有註解。
ps:只有java.lang.annnotation.RetentionPolicy設定為RUNTIME的註解才可以被訪問。
獲取父類
Class<?> ancestor = c.getSuperclass();
note:獲取Class物件c表示的類的父類。
ps:原始型別與Object返回null。
ps:陣列返回Object。
2.3發現類成員
獲取包名
Package p = c.getPackage();
獲取構造器
Constructor[] cs = c.getConstructors();
獲取域
Field[] fs = c.getFields();
ps:java.lang.reflect.Field.isEnumConstant()用於判斷域是否為常量。
獲取方法
Method[] ms = c.getMethods();
獲取內部類
Class[] ccs = c.getClasses();
獲取成員
Member[] mes = c.getFields();
note:使用Member代表域。
ps:Member可以代表域、方法、構造器。
ps:Member沒有包含getGenericString()方法,使用時可以將其轉型。