1 Class類
JAVA反射機制是在運作狀态中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性;這種動态擷取的資訊以及動态調用對象的方法的功能稱為java語言的反射機制。
1.1 擷取Class對象的三種方式:
public class Person {
private String name;
public int age;
static{
System.out.println("靜态代碼塊");
}
public Person(){
System.out.println("空參構造");
}
public Person(String name,int age){
this.name=name;
this.age=age;
System.out.println("Person(String name,int age)");
}
private Person(String name){
this.name=name;
System.out.println("Person(String name)");
}
public void eat(){
System.out.println("公共空參方法");
}
public void sleep(String name){
System.out.println("公共有參方法");
}
public void smoke(){
System.out.println("私有空參構造");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException {
//1.通過getClass方法擷取, 通過對象擷取
Person p=new Person();
Class c1=p.getClass();
System.out.println(c1);
//2.通過類名擷取
Class c2=Person.class;
System.out.println(c2);
System.out.println(c1==c2);
System.out.println(c1.equals(c2));
//3.通過完整的包名+類名擷取
Class c3=Class.forName("com.oracle.demo03.Person");
System.out.println(c3);
}
}
2 通過反射擷取構造方法并使用
在反射機制中,把類中的成員(構造方法、成員方法、成員變量)都封裝成了對應的類進行表示。其中,構造方法使用類Constructor表示。可通過Class類中提供的方法擷取構造方法:
public class Demo02 {
//構造方法 Constructor
//成員變量 Field
//成員方法 Method
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//反射擷取構造方法
//1.擷取Person.Class檔案對象
Class c=Class.forName("com.oracle.demo03.Person");
//擷取所有公共的構造方法(數組)
/*Constructor[]cons=c.getConstructors();
//周遊
for(Constructor con:cons){
System.out.println(con);
}*/
//擷取某個公共構造方法
/*Constructor con1=c.getConstructor(String.class,int.class);
System.out.println(con1);
//通過構造方法建立對象
Object obj=con1.newInstance("張三",18);
System.out.println(obj);*/
//擷取所有構造方法數組
/*Constructor[]cons=c.getDeclaredConstructors();
for(Constructor con:cons){
System.out.println(con);
}*/
//擷取某個私有構造方法
Constructor con=c.getDeclaredConstructor(String.class);
//System.out.println(con);
//暴力反射
con.setAccessible(true);
Object obj=con.newInstance("熊大");
System.out.println(obj);
}
}
3 通過反射擷取成員變量和成員方法并使用
在反射機制中,把類中的成員變量使用類Field表示。可通過Class類中提供的方法擷取成員變量:
在反射機制中,把類中的成員方法使用類Method表示。可通過Class類中提供的方法擷取成員方法:
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException {
//擷取位元組碼檔案對象
Class c=Class.forName("com.oracle.demo01.Person");
//擷取所有的成員變量
/*Field[]fields=c.getDeclaredFields();
//周遊
for(Field field:fields){
System.out.println(field);
}*/
//擷取某個成員變量并指派
/*Field field=c.getDeclaredField("age");
Object obj=new Person();
field.set(obj, 18);
System.out.println(obj);*/
//擷取所有成員方法
/*Method[]methods=c.getDeclaredMethods();
//周遊
for(Method method:methods){
System.out.println(method);
}*/
//擷取單個成員方法
Method method=c.getMethod("sleep", String.class);
//調用方法
Object obj=c.newInstance();
method.invoke(obj, "張三");
4 反射練習
4.1 泛型擦除
思考,将已存在的ArrayList<Integer>集合中添加一個字元串資料,如何實作呢?
其實程式編譯後産生的.class檔案中是沒有泛型限制的,這種現象我們稱為泛型的擦除。那麼,我們可以通過反射技術,來完成向有泛型限制的集合中,添加任意類型的元素
public class Demo02 {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
//泛型擦除
ArrayList<Integer>arr=new ArrayList<Integer>();
//擷取ArrayList的位元組碼檔案對象
Class c=arr.getClass();
//通過反射的方式擷取add方法
Method add=c.getMethod("add", Object.class);
add.invoke(arr, "aaa");
System.out.println(arr);
}
}
4.2 反射配置檔案
通過反射配置檔案,運作配置檔案中指定類的對應方法
public class Demo01 {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
//明确配置檔案的路徑
FileReader fr=new FileReader("src/com/oracle/demo02/config.properties");
//建立Properties集合
Properties pro=new Properties();
//從配置檔案中讀取鍵值對到集合中
pro.load(fr);
//從集合中擷取完整的包名+類名
String ClassName=pro.getProperty("ClassName");
//擷取方法名
String MethodName=pro.getProperty("MethodName");
//通過反射擷取位元組碼檔案對象
Class c=Class.forName(ClassName);
//建立對象
Object obj=c.newInstance();
//擷取方法
Method method=c.getMethod(MethodName);
//調用方法
method.invoke(obj);
}
}