深入理解 Java 反射:Class (反射的入口)
什麼是 Reflection 反射,為什麼要用它 Java 強型別語言,但是我們在執行時有了解、修改資訊的需求,包括類資訊、成員資訊以及陣列資訊。
Java 中 Reflection 和 Introspection 區別? 說起反射,還有一個相似的概念 ‘Introspection’,字面意思是“自省、內省”,它們之間的區別如下:
內省 在執行時檢查一個物件的型別或者屬性 最常見的例子就是執行時通過 a instanceof A 來判斷 a 物件的型別 反射 用來在執行時檢查或者修改一個物件資訊 可以用來實現看似不可能的操作,比如訪問私有方法,動態建立物件 可以看到,反射是在內省的基礎上,增加了修改的能力。
反射的入口:java.lang.Class 日常開發中的物件,分為兩種,基本型別和引用型別:
基本型別,(固定的 8 種) 整數:byte, short, int, long 小數:float, double 字元:char 布林值:boolean 引用型別 所有的引用型別都繼承自 java.lang.Object 類,列舉,陣列,介面都是引用型別 java.io.Serializable 介面,基本型別的包裝類(比如 java.lang.Double)也是引用型別 對每一種物件,JVM 都會例項化一個 java.lang.Class 的例項,java.lang.Class 為我們提供了在執行時訪問物件的屬性和型別資訊的能力。Class 還提供了建立新的類和物件的能力。最重要的是,Class 是呼叫其他反射 API 的入口,我們必須先獲得一個 Class 例項才可以進行接下來的操作。
得到一個 Class 物件 除了 java.lang.reflect.ReflectPermission 以外,java.lang.reflect 中的其他類都沒有 public 的建構函式,也就是說要得到這些類,我們必須通過 Class 。
下面是幾種得到 Class 物件的不同方法:
1.Object.getClass 方法
如果我們已經拿到了一個物件,可以很方便地使用它的 getClass 方法獲得一個 Class 物件(當然這僅限於引用型別的物件):
Class c = "shixinzhang.top".getClass(); 1 返回的物件 c 是 String 型別。
enum Sex{ FEMALE, MALE }
Class c = FEMALE.getClass(); 上述例子中 FEMALE 是 列舉 Sex 的例項,因此 FEMALE.getClass() 返回的就是 列舉型別 Sex 的 Class。
byte[] bytes = new byte[1024]; Class<? extends byte[]>c = bytes.getClass(); 1 2 由於陣列也是 Object 的一種,因此我們可以呼叫 getClass() 方法獲得 byte 陣列型別的 Class。
2. .class 語法
如果我們當前沒有某個類的物件,無法使用 getClass() 方法,那還可以使用另外一種方法獲取 Class:在要獲得的類名後加上 .class ,比如這樣:
Integer.class.newInstance(); int.class.newInstance() 1 2 可以看到,這種方式不僅能用於引用型別,基本型別也可以。
當然陣列也可以嘍:
Class b = int[][].class; 1 3.Class.forName()
如果我們有一個類的完整路徑,就可以使用 Class.forName(“類完整的路徑”) 來得到相應的 Class,這個方法只能用於引用型別,比如:
Class<?> c = Class.forName("java.lang.String"); Class<?> aClass = Class.forName("top.shixinzhang.androiddemo2.beans.BookBean"); 4.靜態屬性 TYPE
上面介紹,使用 .class 字尾可以很方便地獲得基本型別的 Class。
對於基本型別和 void 的包裝類,還有另外一種方式獲得 Class,那就是靜態屬性 TYPE 。
每個包裝類都有 TYPE 屬性,以 Double 為例:
public static final Class<Double> TYPE = (Class<Double>) double[].class.getComponentType(); 可以看到這個屬性就是使用 .class 的方式獲得 Class 並儲存。
因此我們可以直接呼叫包裝類的 TYPE:
Class<Integer> integerWrapper = Integer.TYPE; Class<Double> doubleWrapper = Double.TYPE; Class<Void> voidWrapper = Void.TYPE; 5.返回 Class 的方法
如果我們已經有了一個 Class,可以使用下面的一些方法來獲得它相關的類:
Class.getSuperclass() 返回呼叫類的父類 Class.getClasses() 返回呼叫類的所有公共類、介面、列舉組成的 Class 陣列,包括繼承的 Class.getDeclaredClasses() 返回呼叫類顯式宣告的所有類、介面、列舉組成的 Class 陣列 Class.getDeclaringClass() java.lang.reflect.Field.getDeclaringClass() java.lang.reflect.Method.getDeclaringClass() java.lang.reflect.Constructor.getDeclaringClass() 返回類/屬性/方法/構造器所在的類 Class 的修飾符:Modifier 一個 Class 可以被以下修飾符的一種或者多種修飾:
訪問許可權控制符:public, protected, private 抽象的、需要實現的:abstract 限制只能有一個例項的:static 不允許修改的:final 執行緒同步鎖:synchronized 原生函式:native 採用嚴格的浮點精度:strictfp 介面 註解 當然上面的修飾符不是所有 Class 都可以修飾,比如:
Interface 不能是 final 的 enum 不能是 abstract 的 java.lang.reflect.Modifier 提供了對 Class 修飾符的解碼,我們可以使用 Class.getModifiers() 獲得呼叫類的修飾符的二進位制值,然後使用 Modifier.toString(int modifiers) 將二進位制值轉換為字串,Modifier.toString() 方法實現如下:
public static java.lang.String toString(int modifiers) { StringBuilder buf = new StringBuilder(); if (isPublic(modifiers)) { buf.append("public "); } if (isProtected(modifiers)) { buf.append("protected "); } if (isPrivate(modifiers)) { buf.append("private "); } if (isAbstract(modifiers)) { buf.append("abstract "); } if (isStatic(modifiers)) { buf.append("static "); } if (isFinal(modifiers)) { buf.append("final "); } if (isTransient(modifiers)) { buf.append("transient "); } if (isVolatile(modifiers)) { buf.append("volatile "); } if (isSynchronized(modifiers)) { buf.append("synchronized "); } if (isNative(modifiers)) { buf.append("native "); } if (isStrict(modifiers)) { buf.append("strictfp "); } if (isInterface(modifiers)) { buf.append("interface "); } if (buf.length() == 0) { return ""; } buf.setLength(buf.length() - 1); return buf.toString(); } 注意:
Interface 預設是 abstract 的,雖然我們沒有新增,編譯器會在編譯器為每個 Interface 新增這個修飾符。 只有被 @Retention(RetentionPolicy.RUNTIME) 修飾的註解才可以在執行時被髮射獲取 Java 中預定義的註解 @Deprecated,@Override, 和 @SuppressWarnings 中只有 @Deprecated 可以在執行時被訪問到 Class 的成員:Member java.lang.reflect.Member 是一個介面,代表 Class 的成員,每個成員都有型別,分為是否從父類繼承,還有是否可以直接訪問。
Member 有三個實現類:
java.lang.reflect.Constructor:表示該 Class 的建構函式 java.lang.reflect.Field:表示該 Class 的成員變數 java.lang.reflect.Method:表示該 Class 的成員方法 獲取建構函式 java.lang.Class 提供了以下方法用於獲取該類的建構函式:
注意:建構函式無法從父類繼承
獲取成員變數 java.lang.Class 提供了以下方法用於獲取該類的成員變數:
獲取成員方法 java.lang.Class 提供了以下方法用於獲取該類的成員方法: