反射

1、Class對象的獲取有三種方式:
(1)任何類的對象可以通過調用Object類提供的**getClass()取得該類Class對象;
(2)類名稱.class可以直接根據某個具體類來取得其Class對象
(3)調用Class類的靜態方法
Class.forName(String className)**傳入類的全名稱來取得其Class對象
且任何一個類的Class對象由JVM加載後產生(該Class對象在JVM中全局唯一)

public class Test1 {
    public static void main(String[] args) {
        /*根據類正向產生對象*/
        Date date=new Date();
        System.out.println(date);
       /*
       * 反射
       * */
       //1.類對象.getClass
        System.out.println(date.getClass());
        //2.類名稱.class
        System.out.println(Date.class);
        //3.Class.forName(String className)
        try {
            System.out.println(Class.forName("java.util.Date"));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        /*任何一個類的class對象有且只有一個*/
        System.out.println(date.getClass()==Date.class);//true
        try {
            System.out.println(date.getClass()==Class.forName("java.util.Date"));//true
            System.out.println(Class.forName("java.util.Date")==Date.class);//true
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

2、根據反射取得一個類的Class對象後,可以通過反射來實例化對象,在Class類中有如下方法:
(1) public T newInstance() throws InstantiationException, IllegalAccessException
這種方法只能調用無參構造,並且無參構造必須是public權限;
方法是: 類對象.newInstance();

public class CreateObject {
    public static void main(String[] args) throws Exception {
        /*1.獲取類的Class對象*/
        Class<?> cls=Class.forName("java.util.Date");
        /*2.通過反射取得Date的實例化對象*/
        Date date=cls.newInstance();
        System.out.println(date);
    }
}

(2)還有一種是Constructor類提供的實例化對象的方法:
public T newInstance(Object … initargs)
方法是:在使用newInstance之前,要先獲取構造方法Constructor,再對象.newInstance(…);括號內是要賦予對象屬性的值;
而要獲取本類中有參構造方法的方式有:
public Constructor getDeclaredConstructor(Class<?>… parameterTypes)
或者 public Constructor getConstructor(Class<?>… parameterTypes)

class Parent {
    private String name;
    private Integer age;
    public Parent(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Parent{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class CreateObject2 {

    public static void main(String[] args) {

        Class<?> cls = Parent.class;
        /*獲取構造方法*/
        try {
     //如果類中的構造方法是私有的,getDeclaredConstructor能夠拿到該構造方法,但是不能實例化對象
     //要傳入獲取特定構造方法中的屬性的class對象
            Constructor constructor = cls.getDeclaredConstructor(String.class, Integer.class);
            Parent parent = (Parent) constructor.newInstance("張三", 14);//傳入實例化的屬性值
            System.out.println(parent);
        } catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }

    }
}

3.根據反射可以獲取類的方法

取得類中指定名稱的普通方法
public Method getMethod(String name, Class<?>… parameterTypes)

public Method getDeclaredMethod(String name, Class<?>… parameterTypes)

既要傳名稱又要傳類型,是因爲:方法有重載;

取得類中全部普通方法
public Method[] getMethods() throws SecurityException

:取得本類以及父類中所有public方法,

public Method[] getDeclaredMethods() throws SecurityException

:取得本類中所有全部普通方法,包含私有方法;

Method類中提供調用類中普通方法的API:
public Object invoke(Object obj, Object… args) 傳入實例化對象和獲取到的方法的參數值

        //先獲取類對象
          Class<?> cls= Per.class;
          /*創建實例化對象*/
            Per per= (Per) cls.newInstance();
            /*拿到這個類中的setName的方法,傳入方法的名稱,如果該方法有參數,還要傳入參數的類型*/
           Method method= cls.getMethod("setName", String.class);
           /*通過invoke進行調用,invoke方法內要傳入創建好的實例化對象,如果該方法有參數再傳入要賦予該對象的值*/
            method.invoke(per,"李四");

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章