反射是什麼? 是指在程式運作期間,可以動态建立對象。
(1)獲得位元組碼檔案對象的三種方法
為什麼要擷取位元組碼檔案對象,隻有這樣,才能通過位元組碼檔案對象去建立類的對象,而不是用new,這樣友善了程式的修改。直接修改配置檔案,便可以更改建立的類。
1.Object類的getclass()方法:同一個類的位元組碼隻被加載一次
2.類.class:任何一個類在生成的.class檔案中,會産生一個Class對象,用于表示這個類的類型資訊
3.Class.forName(類名):注意類名的寫法應該是全路徑,包括包名
package demo;
public class test {
public static void main(String[] args) throws ClassNotFoundException {
//1.Object類的getclass() 通過同一個類建立的位元組碼檔案是一樣的,隻被加載一次
Person p1 = new Person();
Person p2 = new Person();
Class class1= p1.getClass();
Class class2= p2.getClass();
System.out.println(class1);
System.out.println(class2);
System.out.println(class1==class2);
//2.類名.class對象
Class class3= Person.class;
System.out.println(class2==class3);
//3.類型名.forName()
Class class4= Class.forName("demo.Person");//注意是包名.類名
System.out.println(class3==class4);
//結果是:
class demo.Person
class demo.Person
true
true
true
(2)位元組碼檔案對象裡面有什麼
類 | 位元組碼檔案對象 |
---|---|
構造方法 | 構造方法對象(類型為constructor) |
成員變量 | 成員變量對象(類型為filed) |
成員函數 | 成員函數對象(類型為method) |
(3)用位元組碼檔案對象來建立一個類的對象
------------------------------------------------Person2.java
package demo;
public class Person2 {
public Person2(){};//類的構造方法1
public Person2(String name,int age){//類的構造方法2
super();
this.name=name;
this.age=age;
}
private String name;
private int age;
public void eat(){
System.out.println("吃吃吃222");
}
}
------------------------------------------------test.java
package demo;
public class test {
public static void main(String[] args) {
// Person p=new Person(); 這是傳統的建立對象的方法
//讀取配置檔案中類的資訊,想建立什麼類就建立什麼,可在外部配置檔案中修改
FileReader f=new FileReader("aa.txt");
BufferedReader br=new BufferedReader(f);
String str=br.readLine();
System.out.println(str);
//--------------第一步:用Class.forName()來建立位元組碼檔案對象
Class clazz=Class.forName(str);
//--------------第二步:擷取類中的構造器對象
//獲得Person類的構造方法,用Constructor數組來存儲一共有幾個(隻能得到public的構造方法)
Constructor[] constructors =clazz.getConstructors();
System.out.println(constructors.length);
System.out.println(constructors[0]);//輸出構造方法1
System.out.println(constructors[1]);//輸出構造方法2
//--------------第三步:選擇其中一個,用newInstance()來建立對象
Constructor c=constructors[0];
//傳回的是Object類型,再進行類型轉換
Object obj=c.newInstance();
//相當于建立了一個Person2類的對象 a ,不是以前傳統的用new建立的
Person2 a=(Person2) obj;
a.eat();
}
}
//結果為:2
public demo.Person2()
public demo.Person2(java.lang.String,int)
吃吃吃222
(4)得到位元組碼檔案對象中的成員方法對象Method
1.擷取位元組碼檔案對象
2.得到某個特定的方法 【要知道方法名+形參】
3.建立對象【調用的傳統方法是對象.方法(對象),但反射裡面是:方法.invoke(對象,實參)】
4.反射調用
package demo;
public class Person2 {
Person2(String name){//類的構造方法3
super();
this.name=name;
}
private String name;
public void setName(String name) {
this.name = name;
System.out.println(name);
}
}
package demo;
//-----------------------得到位元組碼中的成員方法對象 Method
public class test2 {
public static void main(String[] args) {
//--------------第一步:得到位元組碼檔案對象
Class clazz=Class.forName("demo.Person2");
//Method[] methods= clazz.getMethods();//父類繼承下來的+自身的+public,才可以顯示出來
//增強型的for循環。Method是元素類型,method是每一個元素變量,methods是你要周遊的數組
//for(Method method:methods)
//System.out.println(method);
//--------------第二步:得到特定的方法 要知道方法名+形參。
Method method=clazz.getMethod("setName",String.class);
System.out.println(method);
// Constructor constructor=clazz.getConstructor(); 傳統方法是用構造器去建立執行個體
//Object newInstance=constructor.newInstance();
//--------------第三步:建立方法所在類的對象,是更便捷的方法,但隻針對無參數
Object newInstance=clazz.newInstance();
//--------------第四步:反射調用
Object a=method.invoke(newInstance,"haha");
}
}
//結果是:public void demo.Person2.setName(java.lang.String)
haha