09 Java SE 反射
By Kevin Song
定義:反射機制是在運行狀態中,對於任意一個類(class文件),都能知道這個類的所有方法和屬性。對於任意一個對象都能調用它的任意一個方法和屬性。
Tomcat例
- Tomcat App提供 Servlet接口
- MyServlet類實現Servlet接口
- 編寫MyServlet類配置文件
- Tomcat直接讀取配置文件來動態獲取MyServlet類中的方法和屬性
- Tomcat通過Class類來獲取MyServlet類字節碼文件中的內容(想要對MyServlet文件進行內容獲取,第一步要獲取該類的字節碼文件對象即可)
- 獲取Class類中的對象(字節碼文件對象)
- Tomcat通過Class類中的forName()方法獲取MyServlet類字節碼文件對象
- 獲取Class類中的構造方法
- 通過newInstance()獲取該類空構造方法對象
- 通過getConstructor獲取構造方法對象
- 再通過構造方法對象newInstance();方法來創建非空參對象
- 獲取Class類中的字段
- 獲取Class類中的方法
- 獲取Class類中的對象(字節碼文件對象)
- Tomcat通過Class類來獲取MyServlet類字節碼文件中的內容(想要對MyServlet文件進行內容獲取,第一步要獲取該類的字節碼文件對象即可)
class Person {
name;
age;
}
Person p1 = new Person(Leo, 20);
Person P2 = new Person(Kylo, 28);
//描述字節碼文件的類
class Class {
提供可以獲取字節碼文件的內容(字段,構造方法,一般方法)
}
class Demo {
int a = 6;
Demo() {}
void show() {}
}
class Test {
int b = 9;
Test() {}
void abc() {}
}
獲取Class對象
三種方式
- 方式三:Object類中的getClass()方法
- 必須明確具體的類並且創建對象
- 方式二:任何數據類型都具備一個靜態的屬性.class來獲取其對應的class對象
- 要明確類中的靜態成員
- 方式三:通過給定的類的字符串名稱就可以獲取該類
- Class類中的forName()方法
public class ReflectDemo {
public static void main(String[] args) {
//方式一:Object類中的getClass()方法
public static void getClassObject_1() {
Person p = new Person();
Class clazz = p.getClass();
Person p1 = ne Person();
Class clazz1 = p1.getClass();
System.out.println(clazz==clazz1);//true
}
//方式二
public static void getClassObject_2() {
Class clazz = Person.class;
Class clazz1 = Person.class;
System.out.println(clazz==clazz1);//true
}
//方式三
public static void getClassObject_3() throws ClassNotFoundException {
String className ="Person";
Class class = Class.forName(className);
System.out.println(clazz);
}
}
}
public class Person {
private int age;
private String name;
public Person(int age, String name) {
super();
this.age = age;
this.name = name;
System.out.println(personParam run"");
}
public Person() {
super;
System.out.println(person run"");
}
public void show() {
System.out.println(name+"..."+age);
}
private void method() {
System.out.println("method run");
}
public void paraMethod(String str, int num) {
System.out.println("paramMethod run"+str+":"+num);
}
public static void staticMethod() {
System.out.println("staticMethod run");
}
}
獲取Class中的構造方法
- 早期創建對象
- new的時候,先根據被new的類的名稱找尋該類的字節碼文件,並加載進內創建該字節碼文件對象,然後創建該字節文件的對應Person對象
- 反射創建對象
- 只要知道類名,通過Class來創建該類字節碼文件對象
- 通過newInstance()獲取該類空構造方法對象
- 通過getConstructor獲取構造方法對象
- 再通過構造方法對象newInstance();方法來創建非空參對象
- 只要知道類名,通過Class來創建該類字節碼文件對象
public class ReflectDemo2 {
public static void main(String[] args) {
createNewObject_1();
createNewObject_2();
}
//空參數構造方法
public static void createNewObject_1() {
//以前
Person p = new Person();
//反射
String name = "Person";
Class clazz = Clazz.forName(name);//獲取Person類字節碼文件對象
Object obj = clazz.newInstance();//產生Person類對象
}
//非空參數構造方法
public static void createNewObject_2() {
String name = "Person";
Class clazz = Clazz.forName(name);//獲取Person類字節碼文件對象
//獲取指定構造函數的對象
Constructor constructor = clazz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("Kylo", 29);
}
}
獲取Class中的字段
public class ReflectDemo3 {
public static void main(String[] args) {
createNewObject_1();
createNewObject_2();
}
//空參數構造方法
public static void getFieldDemo() {
Class clazz = Class.forName("Person");
Field field = clazz.getField("age");//獲取公有的
field = clazz.getDeclaredField("age");//獲取本類,包含私有
//對私有字段的訪問取消權限檢查,強制訪問
field.setAccessible(true);
Object obj = clazz.newInstance();
field.set(obj,20);
Object o = field.get(obj);
System.out.println(o);
}
}
獲取Class中的方法
public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
getMethodDemo_3();
}
//獲取有參方法
public static void getMethodDemo_3() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getMethod("paramMethod", String.class,int.class);
Object obj = clazz.newInstance();
method.invoke(obj, "小強",89);
}
//獲取無參方法
public static void getMethodDemo_2() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getMethod("show", null);//獲取空參數一般方法。
//Object obj = clazz.newInstance();
Constructor constructor = clazz.getConstructor(String.class,int.class);
Object obj = constructor.newInstance("小明",37);
method.invoke(obj, null);
}
//獲取指定Class中的所有公共方法
public static void getMethodDemo() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
Method[] methods = clazz.getMethods();//獲取的都是公有的方法。
methods = clazz.getDeclaredMethods();//只獲取本類中所有方法,包含私有。
for(Method method : methods){
System.out.println(method);
}
}
}
反射練習
public class Mainboard {
public void run() {
System.out.println("main board run....");
}
public void usePCI(PCI p) {//PCI p = new SouncCard();
if (p != null) {
p.open();
p.close();
}
}
}
public class SoundCard implements PCI {
public void open(){
System.out.println("sound open");
}
public void close(){
System.out.println("sound close");
}
}
public class NetCard implements PCI {
@Override
public void open() {
System.out.println("net open");
}
@Override
public void close() {
System.out.println("net close");
}
}
public interface PCI {
public void open();
public void close();
}
/*
* 電腦運行。
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
Mainboard mb = new Mainboard();
mb.run();
//每次添加一個設備都需要修改代碼傳遞一個新創建的對象
//mb.usePCI(new SoundCard());
//能不能不修改代碼就可以完成這個動作。
//不用new來完成,而是隻獲取其class文件。在內部實現創建對象的動作。
File configFile = new File("pci.properties");
Properties prop = new Properties();
FileInputStream fis = new FileInputStream(configFile);
prop.load(fis);
for(int x=0; x<prop.size(); x++){
String pciName = prop.getProperty("pci"+(x+1));
Class clazz = Class.forName(pciName);//用Class去加載這個pci子類。
PCI p = (PCI)clazz.newInstance();
mb.usePCI(p);
}
fis.close();
}
}
pci.properties文件
pci1=cn.itcast.reflect.test.SoundCard
pci2=cn.itcast.reflect.test.NetCard