1、反射概念
是程式可以通路、檢測和修改它本身狀态或行為的一種能力。Java中的反射,能夠建立靈活的代碼,這些代碼可在運作時裝配,無需在元件之間進行源代碼連結。簡單的說就是:通過class檔案對象,去使用該檔案中的成員變量,構造方法,成員方法。每個類都有一個Class對象,每當編寫并且編譯了一個新類,就會産生一個Class對象【被儲存在一個同名的.class檔案中】所有的類都是在對其第一次使用的時候,動态加載到JVM中。Class對象僅在需要的時候才被加載,static初始化是在類加載時進行的。一旦某個類的Class對象被載入記憶體,它就被用來建立這個類的所有對象。Class類與java.lang.reflect類庫一起對反射的概念進行了支援,該類包含了Filed,Method,Constructor類,這些類型的對象由JVM在運作時建立,用以表示未知類裡對應的成員。這樣就可以使用Constructor建立新的對象,使用它get( ), set( )方法讀取和修改與Field對象關聯的字段,用invoke( )方法調用Method對象關聯的方法。另外,還可以調用getFields()、getMethods( )和getConstructor( )等方法,以傳回表示字段、方法、以及構造器的對象的數組。這樣匿名對象的類資訊就可以在運作的時候被完全确定下來,而在編譯時不需要知道任何事情。
2、如何擷取Class對象的引用
擷取Class對象的引用【傳回表示該對象實際類型的Class引用】的方法,常用的有3種:
(1)Object類的getClass()方法:如果我們已經擁有我們所需要類型的對象,就可以通過調用getClass()方法擷取Class引用。
(2)類字面常量,資料類型的靜态屬性class
(3)Class類中的靜态方法:public static Class forName(String className).在日常的開發中,常用的是第三種方式擷取Class對象,因為是一個字元串,而不是一個具體的類名。這樣我們就可以把這樣的字元串配置到配置檔案中。
擷取Class對象的引用示例:
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
/*方式1:通過getClass()方法擷取Class對象
* 建立同一個類不同的對象,他們的Class對象是同一個。*/
Person person1 = new Person();
Class clazz1 = person1.getClass();
Person person2 = new Person();
Class clazz2 = person2.getClass();
System.out.println(person1 == person2);// false
System.out.println(clazz1 == clazz2);// true
// 方式2:通過class靜态屬性擷取Class對象
Class clazz3 = Person.class;
System.out.println(clazz1 == clazz3);//true
// 方式3:Class類的靜态方法forName()
Class clazz4 = Class.forName("cn.edu.Person");
System.out.println(clazz1 == clazz4);//true
}
}
3、通過Class對象擷取Constructor對象,并調用構造方法建立執行個體
(1)擷取單個構造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes):
傳回指定參數類型、具有public通路權限的構造函數
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):
傳回指定參數類型、所有聲明的(包括private)構造函數
參數表示的是:你要擷取的構造方法的,構造參數個數,及資料類型的class位元組碼檔案對象
(2)擷取多個構造方法
public Constructor[] getConstructors():所有公共構造方法
public Constructor[] getDeclaredConstructors():所有構造方法
(3)通過獲得的Constructor對象,建立新執行個體
package cn.edu.reflect;
public class Person {
/**
* 3種範圍的成員變量:private, 預設,public
* */
private String name;
int age;
public String address;
/**構造函數:無參, 有參(1,2,3個參數)*/
public Person() {
}
private Person(String name) {
this.name = name;
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
/**
* 成員函數:
* ①public, private
* ②有參,無參
* ③無傳回值(void),有傳回值
* */
public void show() {
System.out.println("show");
}
public void method(String s) {
System.out.println("method " + s);
}
public String getString(String s, int i) {
return s + "---" + i;
}
private void function() {
System.out.println("function");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", address=" + address+ "]";
}
}
public T newInstance(Object... initargs):
使用此 Constructor 對象表示的構造方法來建立該構造方法的聲明類的新執行個體,并用指定的初始化參數初始化該執行個體。
通過反射擷取構造方法并使用一:
package cn.edu.reflect;
import java.lang.reflect.Constructor;
/*通過反射擷取構造方法并使用*/
public class ReflectDemo {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu.reflect.Person");
//1.擷取Constructor[]
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//2.擷取單個預設構造,并且使用獲得的此Constructor 對象,建立類的新執行個體
Constructor con = clazz.getConstructor();//傳回的是構造方法對象
Person person1 = new Person();
System.out.println(person1);
//調用Constructor的newInstance()方法,執行個體化對象
Object obj = con.newInstance();
System.out.println(obj);
Person person2 = (Person)obj;
person2.show();
}
}
/*運作結果如下:
public cn.edu.reflect.Person(java.lang.String,int,java.lang.String)
cn.edu.reflect.Person(java.lang.String,int)
private cn.edu.reflect.Person(java.lang.String)
public cn.edu.reflect.Person()
Person [name=null, age=0, address=null]
Person [name=null, age=0, address=null]
show
* */
通過反射去擷取該構造方法并使用二:
/* public Person(String name, int age, String address)
Person p = new Person("張國榮",,"香港九龍");
System.out.println(p);
*/
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu.reflect.Person");
/*1.擷取帶參構造方法對象*/
Constructor con = clazz.getConstructor(String.class, int.class,String.class);
/*2.通過帶參構造方法對象建立對象*/
Object obj = con.newInstance("張國榮",,"香港九龍");
System.out.println(obj);
}
}
/*Person [name=張國榮, age=47, address=香港九龍]*/
通過反射擷取私有構造方法并使用三:
/*
private Person(String name){}
Person p = new Person("張國榮");
System.out.println(p);
*/
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu.reflect.Person");
Constructor constructor = clazz.getDeclaredConstructor(String.class);
/*用該私有構造方法建立對象,IllegalAccessException:非法的通路異常,
暴力通路,值為true則訓示反射的對象在使用時應該取消Java語言通路檢查。*/
constructor.setAccessible(true);
Object obj = constructor.newInstance("張國榮");
System.out.println(obj);
}
}
/* Person [name=張國榮, age=0, address=null]*/
4、通過Class執行個體擷取成員變量對象,并且使用成員變量
通過發生擷取成員變量并使用
public Field[] getFields():
傳回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或接口的所有可通路公共字段。
public Field getField(String name):
傳回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段
public Field[] getDeclaredFields():
public Field getDeclaredField(String name):
使用代碼執行個體:
public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu.reflect.Person");
//1.擷取所有的成員變量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
//2.通過無參構造方法建立對象
Constructor constructor = clazz.getConstructor();
Object obj = constructor.newInstance();
System.out.println(obj);
/*3.擷取單個的成員變量,擷取address【public】并對其指派
*public void set(Object obj,Object value),第一個參數是要修改字段的對象
* 正被修改對象的字段的新值, 将指定對象變量上此 Field 對象表示的字段設定為指定的新值。
* 給obj對象的addressField字段設定值為"香港.九龍" */
Field addressField = clazz.getField("address");
addressField.set(obj, "香港.九龍");
System.out.println(obj);
// 擷取name【private】并對其指派
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj, "張國榮");
System.out.println(obj);
// 擷取age【預設】并對其指派
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj, );
System.out.println(obj);
}
}
/*
private java.lang.String cn.edu.reflect.Person.name
int cn.edu.reflect.Person.age
public java.lang.String cn.edu.reflect.Person.address
Person [name=null, age=0, address=null]
Person [name=null, age=0, address=香港.九龍]
Person [name=張國榮, age=0, address=香港.九龍]
Person [name=張國榮, age=47, address=香港.九龍]
*/
5、通過Class執行個體擷取Method對象,并調用方法
public Method[] getMethods():
傳回一個包含某些 Method 對象的數組,這些對象反映此 Class 對象所表示的類或接口
(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member方法。
public Method[] getDeclaredMethods():
傳回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,
包括公共、保護、預設(包)通路和私有方法,但不包括繼承的方法。
public Method getMethod(String name,Class
public class ReflectDemo5 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.edu.reflect.Person");
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
Constructor constructor = clazz.getConstructor();
Object obj = constructor.newInstance();
/*1 、擷取單個方法【public,無參數,無傳回值】,并使用: public void show() */
Method method1 = clazz.getMethod("show");
method1.invoke(obj); //調用obj對象的m1方法
/*2 、擷取單個方法【public,有參數,無傳回值】,并使用:public void method(String s) */
Method method2 = clazz.getMethod("method", String.class);
method2.invoke(obj, "hello");
/*3 、擷取單個方法【public,有參數,有傳回值】,并使用:public String getString(String s, int i)*/
Method method3 = clazz.getMethod("getString", String.class, int.class);
String s =(String)method3.invoke(obj, "hello", );
System.out.println(s);
// 、擷取單個方法【private,無參數,無傳回值】,private void function()
Method method4 = clazz.getDeclaredMethod("function");
method4.setAccessible(true);
method4.invoke(obj);
}
}