< 筆記 > Java SE - 09 Java SE 反射

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 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();方法來創建非空參對象
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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章