推薦學習:《》
(1)Reflection(反射)是被視為動態語言的關鍵,反射機制允許程式在執行期 藉助於ReflectionAPI取得任何類的內部資訊,並能直接操作任意物件的內 部屬性及方法。
(2)載入完類之後,在堆記憶體的方法區中就產生了一個Class型別的物件(一個類只有一個Class物件),這個物件就包含了完整的類的結構資訊。我們可以通過這個物件看到類的結構。這個物件就像一面鏡子,透過這個鏡子看到類的結構,所以,我們形象的稱之為:反射。
(1)動態語言
是一類在執行時可以改變其結構的語言:例如新的函數、物件、甚至程式碼可以 被引進,已有的函數可以被刪除或是其他結構上的變化。通俗點說就是在執行時程式碼可以根據某些條件改變自身結構。
主要動態語言:Object-C、C#、JavaScript、PHP、Python、Erlang。
(2)靜態語言
與動態語言相對應的,執行時結構不可變的語言就是靜態語言。如Java、C、C++。Java不是動態語言,但Java可以稱之為「準動態語言」。即Java有一定的動態性,我們可以利用反射機制、位元組碼操作獲得類似動態語言的特性。 Java的動態性讓程式設計的時候更加靈活!
(3)Java反射機制研究及應用
Java反射機制提供的功能
- 在執行時判斷任意一個物件所屬的類
- 在執行時構造任意一個類的物件
- 在執行時判斷任意一個類所具有的成員變數和方法
- 在執行時獲取泛型資訊 在執行時呼叫任意一個物件的成員變數和方法
- 在執行時處理註解 生成動態代理
反射相關的主要API
- java.lang.Class:代表一個類
- java.lang.reflect.Method:代表類的方法
- java.lang.reflect.Field:代表類的成員變數
- java.lang.reflect.Constructor:代表類的構造器 … …
程式經過
javac.exe
命令以後,會生成一個或多個位元組碼檔案(.class
結尾)。
接著我們使用java.exe
命令對某個位元組碼檔案進行解釋執行。相當於將某個位元組碼檔案載入到記憶體中。此過程就稱為類的載入。載入到記憶體中的類,我們就稱為執行時類,此執行時類,就作為Class
的一個範例。
換句話說,
Class
的範例就對應著一個執行時類。
載入到記憶體中的執行時類,會快取一定的時間。在此時間之內,我們可以通過不同的方式來獲取此執行時類。
當程式主動使用某個類時,如果該類還未被載入到記憶體中,則系統會通過如下三個步驟來對該類進行初始化。
類的載入:將
class
檔案位元組碼內容載入到記憶體中,並將這些靜態資料轉換成方法區的執行時資料結構,然後生成一個代表這個類的java.lang.Class
物件,作為方法區中類資料的存取入口(即參照地址)。所有需要存取和使用類資料只能通過這個Class物件。這個載入的過程需要類載入器參與。
類的連結:將Java類的二進位制程式碼合併到JVM的執行狀態之中的過程。
● 驗證:確保載入的類資訊符合JVM規範,例如:以cafe開頭,沒有安全方面的問題
● 準備:正式為類變數(static
)分配記憶體並設定類變數預設初始值的階段,這些記憶體 都將在方法區中進行分配。
● 解析:虛擬機器器常數池內的符號參照(常數名)替換為直接參照(地址)的過程。
類的初始化:
● 執行類構造器【clinit
】()方法的過程。類構造器【clinit
】()方法是由編譯期自動收集類中 所有類變數的賦值動作和靜態程式碼塊中的語句合併產生的。(類構造器是構造類信 息的,不是構造該類物件的構造器)。
● 當初始化一個類的時候,如果發現其父類別還沒有進行初始化,則需要先觸發其父類別 的初始化。
● 虛擬機器器會保證一個類的()方法在多執行緒環境中被正確加鎖和同步。
public class ClassLoadingTest { public static void main(String[] args) { System.out.println(A.m); } } class A { static { m = 300; } static int m = 100; } //第二步:連結結束後m=0 //第三步:初始化後,m的值由<clinit>()方法執行決定 // 這個A的類構造器<clinit>()方法由類變數的賦值和靜態程式碼塊中的語句按照順序合併產生,類似於 // <clinit>(){ // m = 300; // m = 100; // }
類的主動參照(一定會發生類的初始化)
- 當虛擬機器器啟動,先初始化
main
方法所在的類new
一個類的物件- 呼叫類的靜態成員(除了final常數)和靜態方法
- 使用
java.lang.reflect
包的方法對類進行反射呼叫- 當初始化一個類,如果其父類別沒有被初始化,則先會初始化它的父類別
類的被動參照(不會發生類的初始化)
- 當存取一個靜態域時,只有真正宣告這個域的類才會被初始化
- 當通過子類參照父類別的靜態變數,不會導致子類初始化
- 通過陣列定義類參照,不會觸發此類的初始化
- 參照常數不會觸發此類的初始化(常數在連結階段就存入呼叫類的常數池中了)
類載入的作用:將class檔案位元組碼內容載入到記憶體中,並將這些靜態資料轉換成方法區的執行時資料結構,然後在堆中生成一個代表這個類的java.lang.Class物件,作為 方法區中類資料的存取入口。
類快取:標準的JavaSE類載入器可以按要求查詢類,但一旦某個類被載入到類載入器 中,它將維持載入(快取)一段時間。不過JVM垃圾回收機制可以回收這些Class物件。
不同型別的類的載入器:
@Test public void test1(){ //對於自定義類,使用系統類載入器進行載入 ClassLoader classLoader = ClassLoaderTest.class.getClassLoader(); System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2:系統類載入器 //呼叫系統類載入器的getParent():獲取擴充套件類載入器 ClassLoader classLoader1 = classLoader.getParent(); System.out.println(classLoader1);//sun.misc.Launcher$ExtClassLoader@279f2327:擴充套件類載入器 //呼叫擴充套件類載入器的getParent():無法獲取引導類載入器 //引導類載入器主要負責載入java的核心類庫,無法載入自定義類的。 ClassLoader classLoader2 = classLoader1.getParent(); System.out.println(classLoader2);//null ClassLoader classLoader3 = String.class.getClassLoader(); System.out.println(classLoader3);//null }
使用系統類載入器讀取
Properties
組態檔。
/* Properties:用來讀取組態檔。 */ @Test public void test2() throws Exception { Properties pros = new Properties(); //此時的檔案預設在當前的module下。 //讀取組態檔的方式一:// FileInputStream fis = new FileInputStream("jdbc.properties");// FileInputStream fis = new FileInputStream("src\\jdbc1.properties");// pros.load(fis); //讀取組態檔的方式二:使用ClassLoader //組態檔預設識別為:當前module的src下 ClassLoader classLoader = ClassLoaderTest.class.getClassLoader(); InputStream is = classLoader.getResourceAsStream("jdbc1.properties"); pros.load(is); String user = pros.getProperty("user"); String password = pros.getProperty("password"); System.out.println("user = " + user + ",password = " + password); }}
Class
類在Object
類中定義了以下的方法,此方法將被所有子類繼承:
public final Class getClass()
以上的方法返回值的型別是一個
Class
類,此類是Java
反射的源頭,實際上所謂反射從程式的執行結果來看也很好理解,即:可以通過物件反射求出類的名稱。
物件照鏡子後可以得到的資訊:某個類的屬性、方法和構造器、某個類到底實現了哪些介面。對於每個類而言,
JRE
都為其保留一個不變的Class
型別的物件。
一個Class
物件包含了特定某個結構(class
/interface
/enum
/annotation
/primitivetype
/void
/[]
)的有關資訊。
Class
本身也是一個類
Class
物件只能由系統建立物件
一個載入的類在
JVM
中只會有一個Class
範例
一個Class物件對應的是一個載入到
JVM
中的一個.class
檔案
每個類的範例都會記得自己是由哪個
Class
範例所生成
通過
Class
可以完整地得到一個類中的所有被載入的結構
Class
類是Reflection
的根源,針對任何你想動態載入、執行的類,唯有先獲得相應的
方法名 | 功能說明 |
---|---|
static Class forName(String name) | 返回指定類名 name 的 Class 物件 |
Object newInstance() | 呼叫預設建構函式,返回該Class 物件的一個範例 |
getName() | 返回此Class物件所表示的實體(類、介面、陣列類、基本型別或void )名稱 |
Class getSuperClass() | 返回當前Class 物件的父類別的Class 物件 |
Class [] getInterfaces() | 獲取當前Class 物件的介面 |
ClassLoader getClassLoader() | 返回該類的類載入器 |
Class getSuperclass() | 返回表示此Class 所表示的實體的超類的Class |
Constructor[] getConstructors() | 返回一個包含某些Constructor 物件的陣列 |
Field[] getDeclaredFields() | 返回Field 物件的一個陣列 |
Method getMethod(String name,Class … paramTypes) | 返回一個Method 物件,此物件的形參型別為paramType |
(1)class: 外部類,成員(成員內部類,靜態內部類),區域性內部類,匿名內部類
(2)interface:介面
(3)[]:陣列
(4)enum:列舉
(5)annotation:註解@interface
(6)primitive type:基本資料型別
(7)void
前提:若已知具體的類,通過類的class屬性獲取,該方法最為安全可靠, 程式效能最高
範例:Class clazz1 = String.class;
前提:已知某個類的範例,呼叫該範例的
getClass()
方法獲取Class
物件
範例:Class clazz = 「www.atguigu.com」.getClass();
前提:已知一個類的全類名,且該類在類路徑下,可通過
Class
類的靜態方法forName()
獲取,可能丟擲ClassNotFoundException
範例:Class clazz = Class.forName(「java.lang.String」);
範例:
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(「類的全類名」);
@Testpublic void test1() throws ClassNotFoundException { //方式一:呼叫執行時類的屬性:.class Class clazz1 = Person.class; System.out.println(clazz1);//class com.jiaying.java1.Person //方式二:通過執行時類的物件,呼叫getClass() Person p1 = new Person(); Class clazz2 = p1.getClass(); System.out.println(clazz2);//class com.jiaying.java1.Person //方式三:呼叫Class的靜態方法:forName(String classPath) Class clazz3 = Class.forName("com.jiaying.java1.Person"); Class clazz5 = Class.forName("java.lang.String"); System.out.println(clazz3);//class com.jiaying.java1.Person System.out.println(clazz5);//class java.lang.String System.out.println(clazz1 == clazz2);//true System.out.println(clazz1 == clazz3);//true //方式四:使用類的載入器:ClassLoader (瞭解) ClassLoader classLoader = ReflectionTest.class.getClassLoader(); Class clazz4 = classLoader.loadClass("com.jiaying.java1.Person"); System.out.println(clazz4);//class com.jiaying.java1.Person System.out.println(clazz1 == clazz4);//true}
有了Class物件,能做什麼?
建立類的物件:呼叫
Class
物件的newInstance()
方法
要求:
- 類必須有一個無引數的構造器。
- 類的構造器的存取許可權需要足夠。
難道沒有無參的構造器就不能建立物件了嗎?
不是!只要在操作的時候明確的呼叫類中的構造器,並將引數傳遞進去之後,才可以範例化操作。
步驟如下:
- 通過
Class
類的getDeclaredConstructor(Class … parameterTypes)
取得本類的指定形參型別的構造器- 向構造器的形參中傳遞一個物件陣列進去,裡面包含了構造器中所需的各個引數。
- 通過
Constructor
範例化物件。
(1)根據全類名獲取對應的
Class
物件
String name = 「atguigu.java.Person";Class clazz = null;clazz = Class.forName(name);
(2)呼叫指定引數結構的構造器,生成
Constructor
的範例
Constructor con = clazz.getConstructor(String.class,Integer.class);
(3)通過
Constructor
的範例建立對應類的物件,並初始化類屬性
Person p2 = (Person) con.newInstance("Peter",20);System.out.println(p2);
@Test public void test1() throws IllegalAccessException, InstantiationException { Class<Person> clazz = Person.class; /* newInstance():呼叫此方法,建立對應的執行時類的物件。內部呼叫了執行時類的空參的構造器。 要想此方法正常的建立執行時類的物件,要求: 1.執行時類必須提供空參的構造器 2.空參的構造器的存取許可權得夠。通常,設定為public。 在javabean中要求提供一個public的空參構造器。原因: 1.便於通過反射,建立執行時類的物件 2.便於子類繼承此執行時類時,預設呼叫super()時,保證父類別有此構造器 */ Person obj = clazz.newInstance(); System.out.println(obj); }
//體會反射的動態性 @Test public void test2(){ for(int i = 0;i < 100;i++){ int num = new Random().nextInt(3);//0,1,2 String classPath = ""; switch(num){ case 0: classPath = "java.util.Date"; break; case 1: classPath = "java.lang.Object"; break; case 2: classPath = "com.atguigu.java.Person"; break; } try { Object obj = getInstance(classPath); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); } } } /* 建立一個指定類的物件。 classPath:指定類的全類名 */ public Object getInstance(String classPath) throws Exception { Class clazz = Class.forName(classPath); return clazz.newInstance(); }}
提供具有豐富內容的Person
類
//介面public interface MyInterface { void info();}//註解@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})@Retention(RetentionPolicy.RUNTIME)public @interface MyAnnotation { String value() default "hello";}//父類別public class Creature<T> implements Serializable { private char gender; public double weight; private void breath(){ System.out.println("生物呼吸"); } public void eat(){ System.out.println("生物吃東西"); }}//Person類@MyAnnotation(value="hi")public class Person extends Creature<String> implements Comparable<String>,MyInterface{ private String name; int age; public int id; public Person(){} @MyAnnotation(value="abc") private Person(String name){ this.name = name; } Person(String name,int age){ this.name = name; this.age = age; } @MyAnnotation private String show(String nation){ System.out.println("我的國籍是:" + nation); return nation; } public String display(String interests,int age) throws NullPointerException,ClassCastException{ return interests + age; } @Override public void info() { System.out.println("我是一個人"); } @Override public int compareTo(String o) { return 0; } private static void showDesc(){ System.out.println("我是一個可愛的人"); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", id=" + id + '}'; }}
方法 | 作用 |
---|---|
public Field[] getFields() | 返回此Class 物件所表示的類或介面的public 的Field |
public Field[] getDeclaredFields() | 返回此Class 物件所表示的類或介面的全部Field |
方法 | 作用 |
---|---|
public int getModifiers() | 以整數形式返回此Field 的修飾符 |
public Class<?> getType() | 得到Field 的屬性型別 |
public String getName() | 返回Field 的名稱 |
@Test public void test1(){ Class clazz = Person.class; //獲取屬性結構 //getFields():獲取當前執行時類及其父類別中宣告為public存取許可權的屬性 Field[] fields = clazz.getFields(); for(Field f : fields){ System.out.println(f); } System.out.println(); //getDeclaredFields():獲取當前執行時類中宣告的所有屬性。(不包含父類別中宣告的屬性) Field[] declaredFields = clazz.getDeclaredFields(); for(Field f : declaredFields){ System.out.println(f); } } //許可權修飾符 資料型別 變數名 @Test public void test2(){ Class clazz = Person.class; Field[] declaredFields = clazz.getDeclaredFields(); for(Field f : declaredFields){ //1.許可權修飾符 int modifier = f.getModifiers(); System.out.print(Modifier.toString(modifier) + "\t"); //2.資料型別 Class type = f.getType(); System.out.print(type.getName() + "\t"); //3.變數名 String fName = f.getName(); System.out.print(fName); System.out.println(); } }}
方法 | 作用 |
---|---|
public Method[] getMethods() | 返回此Class 物件所表示的類或介面的public 的方法 |
public Method[] getDeclaredMethods() | 返回此Class 物件所表示的類或介面的全部方法 |
方法 | 作用 |
---|---|
public Class<?> getReturnType() | 取得全部的返回值 |
public Class<?>[] getParameterTypes() | 取得全部的引數 |
public int getModifiers() | 取得修飾符 |
public Class<?>[] getExceptionTypes() | 取得異常資訊 |
@Test public void test1(){ Class clazz = Person.class; //getMethods():獲取當前執行時類及其所有父類別中宣告為public許可權的方法 Method[] methods = clazz.getMethods(); for(Method m : methods){ System.out.println(m); } System.out.println(); //getDeclaredMethods():獲取當前執行時類中宣告的所有方法。(不包含父類別中宣告的方法) Method[] declaredMethods = clazz.getDeclaredMethods(); for(Method m : declaredMethods){ System.out.println(m); } } /* @Xxxx 許可權修飾符 返回值型別 方法名(引數型別1 形參名1,...) throws XxxException{} */ @Test public void test2(){ Class clazz = Person.class; Method[] declaredMethods = clazz.getDeclaredMethods(); for(Method m : declaredMethods){ //1.獲取方法宣告的註解 Annotation[] annos = m.getAnnotations(); for(Annotation a : annos){ System.out.println(a); } //2.許可權修飾符 System.out.print(Modifier.toString(m.getModifiers()) + "\t"); //3.返回值型別 System.out.print(m.getReturnType().getName() + "\t"); //4.方法名 System.out.print(m.getName()); System.out.print("("); //5.形參列表 Class[] parameterTypes = m.getParameterTypes(); if(!(parameterTypes == null && parameterTypes.length == 0)){ for(int i = 0;i < parameterTypes.length;i++){ if(i == parameterTypes.length - 1){ System.out.print(parameterTypes[i].getName() + " args_" + i); break; } System.out.print(parameterTypes[i].getName() + " args_" + i + ","); } } System.out.print(")"); //6.丟擲的異常 Class[] exceptionTypes = m.getExceptionTypes(); if(exceptionTypes.length > 0){ System.out.print("throws "); for(int i = 0;i < exceptionTypes.length;i++){ if(i == exceptionTypes.length - 1){ System.out.print(exceptionTypes[i].getName()); break; } System.out.print(exceptionTypes[i].getName() + ","); } } System.out.println(); } }}
方法 | 作用 |
---|---|
public Constructor<T>[] getConstructors() | 返回此 Class 物件所表示的類的所有public 構造方法。 |
public Constructor<T>[] getDeclaredConstructors() | 返回此 Class 物件表示的類宣告的所有構造方法。 |
方法 | 作用 |
---|---|
public int getModifiers() | 取得修飾符 |
public String getName() | 取得方法名稱 |
public Class<?>[] getParameterTypes() | 取得引數的型別 |
/* 獲取構造器結構 */ @Test public void test1(){ Class clazz = Person.class; //getConstructors():獲取當前執行時類中宣告為public的構造器 Constructor[] constructors = clazz.getConstructors(); for(Constructor c : constructors){ System.out.println(c); } System.out.println(); //getDeclaredConstructors():獲取當前執行時類中宣告的所有的構造器 Constructor[] declaredConstructors = clazz.getDeclaredConstructors(); for(Constructor c : declaredConstructors){ System.out.println(c); } } /* 獲取執行時類的父類別 */ @Test public void test2(){ Class clazz = Person.class; Class superclass = clazz.getSuperclass(); System.out.println(superclass); } /* 獲取執行時類的帶泛型的父類別 */ @Test public void test3(){ Class clazz = Person.class; Type genericSuperclass = clazz.getGenericSuperclass(); System.out.println(genericSuperclass); } /* 獲取執行時類的帶泛型的父類別的泛型 程式碼:邏輯性程式碼 vs 功能性程式碼 */ @Test public void test4(){ Class clazz = Person.class; Type genericSuperclass = clazz.getGenericSuperclass(); ParameterizedType paramType = (ParameterizedType) genericSuperclass; //獲取泛型型別 Type[] actualTypeArguments = paramType.getActualTypeArguments();// System.out.println(actualTypeArguments[0].getTypeName()); System.out.println(((Class)actualTypeArguments[0]).getName()); }/* 獲取執行時類實現的介面 */ @Test public void test5(){ Class clazz = Person.class; Class[] interfaces = clazz.getInterfaces(); for(Class c : interfaces){ System.out.println(c); } System.out.println(); //獲取執行時類的父類別實現的介面 Class[] interfaces1 = clazz.getSuperclass().getInterfaces(); for(Class c : interfaces1){ System.out.println(c); } } /* 獲取執行時類所在的包 */ @Test public void test6(){ Class clazz = Person.class; Package pack = clazz.getPackage(); System.out.println(pack); } /* 獲取執行時類宣告的註解 */ @Test public void test7(){ Class clazz = Person.class; Annotation[] annotations = clazz.getAnnotations(); for(Annotation annos : annotations){ System.out.println(annos); } }}
關於setAccessible方法的使用
Method
和Field
、Constructor
物件都有setAccessible()
方法。
setAccessible
啟動和禁用存取安全檢查的開關。
引數值為
true
則指示反射的物件在使用時應該取消Java語言存取檢查。
提高反射的效率。如果程式碼中必須用反射,而該句程式碼需要頻繁的被 呼叫,那麼請設定為
true
,使得原本無法存取的私有成員也可以存取,引數值為false
則指示反射的物件應該實施Java語言存取檢查。
在反射機制中,可以直接通過
Field
類操作類中的屬性,通過Field
類提供的set()
和get()
方法就可以完成設定和取得屬性內容的操作。
方法 | 作用 |
---|---|
public Field getField(String name) | 返回此Class 物件表示的類或介面的指定的public 的Field |
public Field getDeclaredField(String name) | 返回此Class 物件表示的類或介面的指定的Field |
在Field中:
方法 | 作用 |
---|---|
public Object get(Object obj) | 取得指定物件obj 上此Field 的屬性內容 |
public void set(Object obj,Object value) | 設定指定物件obj 上此Field 的屬性內容 |
程式碼演示:
public class ReflectionTest { @Test public void testField() throws Exception { Class clazz = Person.class; //建立執行時類的物件 Person p = (Person) clazz.newInstance(); //獲取指定的屬性:要求執行時類中屬性宣告為public //通常不採用此方法 Field id = clazz.getField("id"); /* 設定當前屬性的值 set():引數1:指明設定哪個物件的屬性 引數2:將此屬性值設定為多少 */ id.set(p,1001); /* 獲取當前屬性的值 get():引數1:獲取哪個物件的當前屬性值 */ int pId = (int) id.get(p); System.out.println(pId); } /* 如何操作執行時類中的指定的屬性 -- 需要掌握 */ @Test public void testField1() throws Exception { Class clazz = Person.class; //建立執行時類的物件 Person p = (Person) clazz.newInstance(); //1. getDeclaredField(String fieldName):獲取執行時類中指定變數名的屬性 Field name = clazz.getDeclaredField("name"); //2.保證當前屬性是可存取的 name.setAccessible(true); //3.獲取、設定指定物件的此屬性值 name.set(p,"Tom"); System.out.println(name.get(p)); }
通過反射,呼叫類中的方法,通過
Method
類完成。步驟:
- 通過
Class
類的getMethod(String name,Class…parameterTypes)
方法取得 一個Method
物件,並設定此方法操作時所需要的引數型別。- 之後使用
Object invoke(Object obj, Object[] args)
進行呼叫,並向方法中 傳遞要設定的obj
物件的引數資訊。
Object invoke(Object obj, Object … args)
說明:Object
對應原方法的返回值,若原方法無返回值,此時返回null
若原方法若為靜態方法,此時形參
Object obj
可為null
若原方法形參列表為空,則
Object[] args
為null
若原方法宣告為private
,則需要在呼叫此invoke()
方法前,顯式呼叫 方法物件的setAccessible(true)
方法,將可存取private
的方法。
程式碼演示:
/* 如何操作執行時類中的指定的方法 -- 需要掌握 */ @Test public void testMethod() throws Exception { Class clazz = Person.class; //建立執行時類的物件 Person p = (Person) clazz.newInstance(); /* 1.獲取指定的某個方法 getDeclaredMethod():引數1 :指明獲取的方法的名稱 引數2:指明獲取的方法的形參列表 */ Method show = clazz.getDeclaredMethod("show", String.class); //2.保證當前方法是可存取的 show.setAccessible(true); /* 3. 呼叫方法的invoke():引數1:方法的呼叫者 引數2:給方法形參賦值的實參 invoke()的返回值即為對應類中呼叫的方法的返回值。 */ Object returnValue = show.invoke(p,"CHN"); //String nation = p.show("CHN"); System.out.println(returnValue); System.out.println("*************如何呼叫靜態方法*****************"); // private static void showDesc() Method showDesc = clazz.getDeclaredMethod("showDesc"); showDesc.setAccessible(true); //如果呼叫的執行時類中的方法沒有返回值,則此invoke()返回null// Object returnVal = showDesc.invoke(null); Object returnVal = showDesc.invoke(Person.class); System.out.println(returnVal);//null }
程式碼演示:
/* 如何呼叫執行時類中的指定的構造器 */ @Test public void testConstructor() throws Exception { Class clazz = Person.class; //private Person(String name) /* 1.獲取指定的構造器 getDeclaredConstructor():引數:指明構造器的參數列 */ Constructor constructor = clazz.getDeclaredConstructor(String.class); //2.保證此構造器是可存取的 constructor.setAccessible(true); //3.呼叫此構造器建立執行時類的物件 Person per = (Person) constructor.newInstance("Tom"); System.out.println(per); }}
推薦學習:《》
以上就是java反射機制詳細解析(總結分享)的詳細內容,更多請關注TW511.COM其它相關文章!