1. 程式人生 > >深入理解 Java 反射:Class (反射的入口)

深入理解 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 提供了以下方法用於獲取該類的成員變數:

shixinzhang

獲取成員方法 java.lang.Class 提供了以下方法用於獲取該類的成員方法:

shixinzhang