反射的做用html
Java反射描述的是,在運行狀態中:java
一、對於任意一個類,都可以知道這個類的全部屬性和方法算法
二、對於任意一個類,都可以調用它的任意一個屬性和方法數組
之因此強調屬性、方法,是由於屬性、方法是開發者對於一個類最關注的兩個部分。實際上經過反射,不單單能夠獲知類的屬性、方法,還能夠獲知類的父類、接口、包等信息函數
至於反射的原理,不難,Java類加載機制一文中講到了,一個類在加載的時候,會在內存中生成一個表明這個.class文件的java.lang.Class對象,.classs文件裏面就包含了描述這個類的信息的一切內容。至於.class文件,是由Java編譯器(注意是Java編譯器,指的不單單是Javac)編譯而來的,是編譯原理的領域;.class文件結構,網上不少講解了,好比類文件結構,這裏就不講了。測試
其實本文只是總結性的,並無任何複雜或者難以理解的知識點,關注點只是但願用到的時候有個地方能夠方便地查看而已。this
本文用到的實體類spa
定義一下本文用到的實體類,儘可能把這個實體類的內容定義得全一些,以期能說明問題:code
package com.xrq.test19; import java.io.Serializable; import java.util.List; @SuppressWarnings("serial") public class Reflection implements Cloneable, Serializable { private String str; private double d; public boolean b; public static short s; public Reflection() { } public Reflection(String str) { this.str = str; } public Reflection(String str, double d, boolean b) { this.str = str; this.d = d; this.b = b; } private void privateMethod() { } public String publicMethod() { privateMethod(); return null; } public String publicMethod(int i) { return null; } public String publicMethod(int i, double d, List<String> l) { return "Reflection.publicMethod(int i, double d), i = " + i + ", d = " + d; } public static int returnOne() { return 1; } public String toString() { return "str = " + str + ", d = " + d + ", b = " + b; } }
Class和ClassLoaderhtm
和此java.lang.Class相關的Class和ClassLoader對象。測試代碼爲:
public static void main(String[] args) throws Exception { Class<?> c = Class.forName("com.xrq.test19.Reflection"); Reflection[] rs = new Reflection[2]; System.out.println("Class.getClass():" + c.getClass()); // 獲取java.lang.Class的Class對象 System.out.println("Class.getClassLoader():" + c.getClassLoader()); // 獲取類的加載器 System.out.println("Class.getSuperclass():" + c.getSuperclass()); // 獲取父類Class對象 System.out.println("Class.getInterfaces():" + c.getInterfaces()[0] + ", " + c.getInterfaces()[1]); // 獲取類的接口列表,注意返回的是一個數組 System.out.println("Class.getgetComponentType():" + rs.getClass().getComponentType()); // 獲取該數組的Class對象 Reflection r = (Reflection)c.newInstance(); // 根據Class實例化出一個類實例來,默認調用無參構造方法 System.out.println("Class.newInstance():" + r); }
運行結果:
Class.getClass():class java.lang.Class Class.getClassLoader():sun.misc.Launcher$AppClassLoader@63c78e57 Class.getSuperclass():class java.lang.Object Class.getInterfaces():interface java.lang.Cloneable, interface java.io.Serializable Class.getgetComponentType():class com.xrq.test19.Reflection Class.newInstance():str = null, d = 0.0, b = false
Package
Package對象包含有關Java包的實現和規範的版本信息。測試代碼爲:
public static void main(String[] args) throws Exception { Class<?> c = Class.forName("com.xrq.test19.Reflection"); Package p = c.getPackage();
System.out.println("Package.toString():" + p.toString()); //toString() System.out.println("Package.getName():" + p.getName()); // 獲取包名 System.out.println("Package.getImplementationTitle():" + p.getImplementationTitle()); // 獲取包標題 System.out.println("Package.getImplementationVendor():" + p.getImplementationVendor()); // 獲取提供該實現的組織、供應商或公司的名稱 System.out.println("Package.getImplementationVersion():" + p.getImplementationVersion()); // 獲取該實現的版本 System.out.println("Package.isSealed():" + p.isSealed()); // 獲取包是否密封的
運行結果:
Package.toString():package com.xrq.test19 Package.getName():com.xrq.test19 Package.getImplementationTitle():null Package.getImplementationVendor():null Package.getImplementationVersion():null Package.isSealed():false
Field
提供有關類或接口的單個字段的信息,以及對它的動態訪問權限。測試代碼爲:
public static void main(String[] args) throws Exception { Class<?> c = Class.forName("com.xrq.test19.Reflection"); Reflection r = new Reflection(); Field f0 = c.getField("b"); Field f1 = c.getDeclaredField("d"); Field[] fs0 = c.getFields(); Field[] fs1 = c.getDeclaredFields(); System.out.print("Class.getFields():"); // 獲取類中全部public字段,順序即public的Field定義的順序 for (Field f : fs0) System.out.print(f + "\t"); System.out.println(); System.out.print("Class.getDeclaredFields():"); // 獲取類中任意訪問權限的字段,順序即全部Field定義的順序 for (Field f : fs1) System.out.print(f + "\t"); System.out.println(); System.out.println("Class.getField(String name):" + f0); // 根據name獲取類中一個訪問權限爲public的字段 System.out.println("Class.getDeclaredField(String name):" + f1); // 根據name獲取類中一個任意訪問權限的字段 System.out.println(); System.out.println("Field.getName():" + f0.getName()); // 獲取字段名 System.out.println("Field.getType():" + f0.getType()); // 獲取類的類型 System.out.println("Field.getBoolean():" + f0.getBoolean(r)); // 獲取某個實例對象該Field的值,什麼類型的Field就是getXXX(Object obj) System.out.println("Field.getModifiers():" + f0.getModifiers()); // 以整數形式返回此Field對象的Java語言修飾符,如public、static、final等 System.out.println("Field.isAccessible():" + f0.isAccessible()); // 返回Field的訪問權限,對private的Field賦值,必需要將accessible設置爲true,以下 System.out.println(); f1.setAccessible(true); System.out.println("Before setB():" + r); f1.setDouble(r, 1.1); System.out.println("After setB():" + r); // 向對象的指定Field設定值 }
運行結果:
Class.getFields():public boolean com.xrq.test19.Reflection.b public static short com.xrq.test19.Reflection.s Class.getDeclaredFields():private java.lang.String com.xrq.test19.Reflection.str private double com.xrq.test19.Reflection.d public boolean com.xrq.test19.Reflection.b public static short com.xrq.test19.Reflection.s Class.getField(String name):public boolean com.xrq.test19.Reflection.b Class.getDeclaredField(String name):private double com.xrq.test19.Reflection.d Field.getName():b Field.getType():boolean Field.getBoolean():false Field.getModifiers():1 Field.isAccessible():false Before setB():str = null, d = 0.0, b = false After setB():str = null, d = 1.1, b = false
Constructor
提供關於類的單個構造方法的信息以及對它的訪問權限。測試代碼爲:
public static void main(String[] args) throws Exception { Class<?> c = Class.forName("com.xrq.test19.Reflection"); Constructor<?> constructor = c.getConstructor(String.class); Constructor<?>[] constructors = c.getConstructors(); System.out.println("Class.getConstructor(Class<?>... parameterTypes):" + constructor); // 獲取指定參數列表的構造函數 System.out.print("Class.getConstructors():"); // 獲取全部的構造函數 for (Constructor<?> con : constructors) System.out.print(con + "\t"); System.out.println("\n"); System.out.println("Constructor.getName():" + constructor.getName()); // 獲取構造函數名,沒什麼意義,確定是和類同名 System.out.println("Constructor.getModifiers():" + constructor.getModifiers()); // 獲取以整數形式返回的此Constructor對象的Java語言修飾符,如public、static、final等 System.out.println("Constructor.isAccessible():" + constructor.isAccessible()); // 獲取該Constructor的訪問權限 System.out.println("Constructor.getParameterTypes():" + constructor.getParameterTypes()[0]); // 獲取Constructor的參數類型,是個數組 System.out.println("Constructor.isVarArgs():" + constructor.isVarArgs()); // 獲取此Constructor中是否帶了可變數量的參數,即例如"String... str"類型的參數 System.out.println(); Reflection r = (Reflection)constructor.newInstance("123"); // 根據指定的構造方法實例化出一個類的實例來,重要 System.out.println("Constructor.newInstance():" + r); }
運行結果:
Class.getConstructor(Class<?>... parameterTypes):public com.xrq.test19.Reflection(java.lang.String) Class.getConstructors():public com.xrq.test19.Reflection(java.lang.String) public com.xrq.test19.Reflection(java.lang.String,double,boolean) public com.xrq.test19.Reflection() Constructor.getName():com.xrq.test19.Reflection Constructor.getModifiers():1 Constructor.isAccessible():false Constructor.getParameterTypes():class java.lang.String Constructor.isVarArgs():false Constructor.newInstance():str = 123, d = 0.0, b = false
Method
提供關於類或接口上單獨某個方法(以及如何訪問該方法)的信息,所反映的方法多是類方法或實例方法。測試代碼爲:
public static void main(String[] args) throws Exception { Reflection r = new Reflection(); Class<?> c = Class.forName("com.xrq.test19.Reflection"); Method md0 = c.getMethod("publicMethod", int.class, double.class, List.class); Method md1 = c.getDeclaredMethod("privateMethod", new Class[0]); Method[] ms0 = c.getMethods(); Method[] ms1 = c.getDeclaredMethods(); System.out.println("Method.getMethod():" + md0); // 根據方法名和參數列表獲取指定的public方法 System.out.println("Method.getDeclaredMethod():" + md1); // 根據方法名和參數列表獲取指定的任意訪問權限的方法,但不包括繼承的方法 System.out.print("Method.getMethods():"); // 獲取此類包括其父類中全部的public方法 for (Method m : ms0) System.out.print(m + "\t"); System.out.println(); System.out.print("Method.getDeclaredMethods():"); // 返回此類中全部的方法(無訪問權限限制),但不包括繼承的方法 for (Method m : ms1) System.out.print(m + "\t"); System.out.println("\n"); System.out.println("Method.getName():" + md0.getName()); // 獲取方法的名字 System.out.println("Method.isAccessible():" + md0.isAccessible()); // 獲取方法的訪問屬性 System.out.println("Method.isVarArgs():" + md0.isVarArgs()); // 獲取方法是否帶有可變數量的參數 System.out.println("Method.getReturnType():" + md0.getReturnType()); // 獲取方法的返回類型 System.out.println("Method.getParameterTypes():" + md0.getParameterTypes()[0] + ", " + md0.getParameterTypes()[1] + ", " + md0.getParameterTypes()[2]); // 獲取方法的參數類型,數組形式,注意一下和下面的方法的區別 System.out.println("Method.getGenericParameterTypes():" + md0.getGenericParameterTypes()[0] + ", " + md0.getGenericParameterTypes()[1] + ", " + md0.getGenericParameterTypes()[2]); // 獲取方法的參數化(帶泛型)類型,數組形式 System.out.println(); System.out.println(md0.invoke(r, 1, 2.2, new ArrayList<String>())); // 反射調用方法,重要 }
運行結果:
Method.getMethod():public java.lang.String com.xrq.test19.Reflection.publicMethod(int,double,java.util.List) Method.getDeclaredMethod():private void com.xrq.test19.Reflection.privateMethod() Method.getMethods():public java.lang.String com.xrq.test19.Reflection.toString() public java.lang.String com.xrq.test19.Reflection.publicMethod(int) public java.lang.String com.xrq.test19.Reflection.publicMethod(int,double,java.util.List) public java.lang.String com.xrq.test19.Reflection.publicMethod() public static int com.xrq.test19.Reflection.returnOne() public final void java.lang.Object.wait() throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public boolean java.lang.Object.equals(java.lang.Object) public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() Method.getDeclaredMethods():public java.lang.String com.xrq.test19.Reflection.toString() public java.lang.String com.xrq.test19.Reflection.publicMethod(int) public java.lang.String com.xrq.test19.Reflection.publicMethod(int,double,java.util.List) public java.lang.String com.xrq.test19.Reflection.publicMethod() private void com.xrq.test19.Reflection.privateMethod() public static int com.xrq.test19.Reflection.returnOne() Method.getName():publicMethod Method.isAccessible():false Method.isVarArgs():false Method.getReturnType():class java.lang.String Method.getParameterTypes():int, double, interface java.util.List Method.getGenericParameterTypes():int, double, java.util.List<java.lang.String> Reflection.publicMethod(int i, double d), i = 1, d = 2.2
Modifier枚舉值列表
Field、Constructor、Method中都有getModifiers()方法,返回的是表示此對象的Java語言修飾符,詳細看下每一個修飾符對應的枚舉值:
修飾符 | 枚舉值 |
public | 1 |
private | 2 |
protected | 4 |
static | 8 |
final | 16 |
synchronized | 32 |
volatile | 64 |
transient | 128 |
native | 256 |
interface | 512 |
abstract | 1024 |
strict | 2048 |
也就是說若是一個方法是"public static final synchronized"的,那麼這個方法的getModifiers()返回的應該是1 + 8 + 16 + 32 = 57,有興趣的能夠本身試驗一下。
那若是反過來,我有一個值是X,如何經過X知道它是哪一種訪問權限的呢?我的的方法是(寫一個完整的版本,現實中能夠用if...else簡化算法):
一、X先和00000001,也就是1作"&"運算,X&1,非0就是public;
二、X再和00000010,也就是2作"&"運算,X&2,非0就是private;
三、X最後和00000100,也就是4作"&"運算,X&4,非0就是protected
其它幾位也都是同樣的判斷方式。