1. 程式人生 > 實用技巧 >Java的反射機制粗淺學習

Java的反射機制粗淺學習

Java的反射機制

  • JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意方法和屬性;
  • 這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射機制。
  • 反射機制多用於程式執行後才能確定建立的類的場景
  • 首先準備了兩個類,一個介面與一個註解
// 自定義註解
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value();
}
// 自定義介面
public interface MyInterface {
    // 自定義介面
    void myMethod();
}
// Person類
public class Person implements Serializable {
    // attribute
    private int age;
    public String name;
    // method
    private void eat(){
        System.out.println("Person--eat");
    }
    public void sleep(){
        System.out.println("Person--sleep");
    }
}
// Student類
@MyAnnotation("hello")
public class Student extends Person implements MyInterface {
    // 屬性
    private int sno;//學號
    double height;//身高
    protected double weight;// 體重
    public double score;// 成績
    
    // 方法
    public String showInfo(){
        return "我是一名三好學生";
    }

    @MyAnnotation("hi method")
    public String showInfo(int a, int b){
        return "我是一名三好學生,過載方法";
    }

    private void work(int a){
        System.out.println("好好工作,碼農");
    }

    void happy(){
        System.out.println("做人要開心");
    }

    protected int getSno(){
        return sno;
    }

    // 構造器
    public Student(){

    }

    public Student(double weight, double height){
        this.weight = weight;
        this.height = height;
    }

    private Student(int sno){
        this.sno = sno;
    }

    Student(int sno, double height){
        this.sno = sno;
        this.height = height;
    }

    protected Student(int sno,double height,double weight){
        this.sno = sno;
        this.height = height;
        this.weight = weight;
    }

    @Override
    @MyAnnotation("hello mymethod")
    public void myMethod() throws RuntimeException{
        System.out.println("重寫介面方法");
    }

    @Override
    public String toString() {
        return "Student{" +
                "sno=" + sno +
                ", height=" + height +
                ", weight=" + weight +
                ", score=" + score +
                '}';
    }
}

獲取類的構造器與建立物件

  • 反射機制中,無論是進行什麼操作,首先都需要先獲取位元組碼資訊xxx.class,然後才能通過位元組碼資訊完成後續操作
public class Test01 {
    // 這是main方法,實現程式主要邏輯
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 獲取位元組碼資訊
        Class cls = Student.class;

        // 通過位元組碼資訊獲取構造器
        // getConstructors() 只能獲取當前執行時類被public修飾的構造器
        Constructor[] c1 = cls.getConstructors();

        for(Constructor c:c1){
            System.out.println(c);
        }
        System.out.println("---------------------------");

        // getDeclaredConstructors() 獲取執行時,類的全部修飾符的構造器
        Constructor[] c2 = cls.getDeclaredConstructors();

        for(Constructor c: c2){
            System.out.println(c);
        }
        System.out.println("---------------------------");

        // 獲取指定的構造器
        // 什麼都不傳的話,會獲得public修飾的空參構造器
        Constructor con1 = cls.getConstructor();
        System.out.println(con1);

        // 獲取兩個引數的public修飾的有參構造器
        Constructor con2 = cls.getConstructor(double.class, double.class);
        System.out.println(con2);

        // 獲取一個引數的private修飾的有參構造器
        Constructor con3 = cls.getDeclaredConstructor(int.class);
        System.out.println(con3);

        // 使用構造器建立物件
        Object o1 = con1.newInstance();
        System.out.println(o1);

        Object o2 = con2.newInstance(120.5, 180.4);
        System.out.println(o2);
    }
}

獲取類的屬性並進行賦值

public class Test02 {
    // 這是main方法,實現程式主要邏輯
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        // 獲取位元組碼資訊
        Class cls = Student.class;
        
        // 獲取屬性
        // getFields() 獲取執行時類和父類中被public修飾的屬性,包含父類
        Field[] fields = cls.getFields();
        for(Field f:fields){
            System.out.println(f);
        }
        System.out.println("________________________________");

        // getDeclaredFields 獲取執行時類中的所有屬性,不包含父類
        Field[] declaredFields = cls.getDeclaredFields();
        for(Field f:declaredFields){
            System.out.println(f);
        }
        System.out.println("________________________________");

        // 獲取指定屬性
        Field score = cls.getField("score");
        System.out.println(score);

        Field sno = cls.getDeclaredField("sno");
        System.out.println(sno);
        System.out.println("________________________________");

        // 屬性的具體結構
        // 獲取修飾符
        int modifiers = sno.getModifiers();
        System.out.println(modifiers);
        System.out.println(Modifier.toString(modifiers));
        // 獲取屬性的資料型別
        Class type = sno.getType();
        System.out.println(type.getName());
        // 獲取屬性的名字
        System.out.println(sno.getName());
        System.out.println("________________________________");

        // 給屬性賦值 給屬性賦值,必須要有這個類的物件,首先要建立物件才行
        Field sco = cls.getField("score");
        Object obj = cls.newInstance();
        sco.set(obj, 98);
        System.out.println(obj);

    }
}

獲取方法並呼叫方法

public class Test03 {
    // 這是main方法,實現程式主要邏輯
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        // 首先獲取位元組碼資訊
        Class cls = Student.class;

        // 獲取public修飾的方法 包含父類
        Method[] me1 = cls.getMethods();
        for(Method m:me1){
            System.out.println(m);
        }
        System.out.println("________________________");

        // 獲取所有的方法,不包含父類
        Method[] me2 = cls.getDeclaredMethods();
        for(Method m:me2){
            System.out.println(m);
        }
        System.out.println("________________________");

        // 獲取指定方法(無參)
        Method showInfo = cls.getMethod("showInfo");
        System.out.println(showInfo);

        // 獲取指定方法(有參)
        Method showInfo2 = cls.getMethod("showInfo",int.class,int.class);
        System.out.println(showInfo2);

        //獲取private修飾的方法
        Method work = cls.getDeclaredMethod("work",int.class);
        System.out.println(work);
        System.out.println("________________________");

        // 獲取方法的具體結構
        /*
        @註解
        修飾符 返回值型別 方法名(引數列表) throws XXXX{}
         */
        // 方法名
        System.out.println(work.getName());
        // 修飾符
        int modifiers = work.getModifiers();
        System.out.println(Modifier.toString(modifiers));
        // 返回值
        System.out.println(work.getReturnType());
        // 引數列表
        Class[] parameterTypes = work.getParameterTypes();
        for(Class c:parameterTypes){
            System.out.println(c);
        }
        // 註解
        Method myMethod = cls.getMethod("myMethod");
        Annotation[] annotations = myMethod.getAnnotations();
        for(Annotation a:annotations){
            System.out.println(a);
        }
        // 異常
        Class[] exceptionTypes = myMethod.getExceptionTypes();
        for(Class c:exceptionTypes){
            System.out.println(c);
        }
        System.out.println("________________________");

        // 呼叫方法
        Object o = cls.newInstance();
        myMethod.invoke(o);

        System.out.println(showInfo2.invoke(o, 12, 14));
    }
}

獲取類的結構相關資訊

public class Test04 {
    // 這是main方法,實現程式主要邏輯
    public static void main(String[] args) {
        // 獲取位元組碼資訊
        Class cls = Student.class;

        // 獲取執行時類的介面
        Class[] interfaces = cls.getInterfaces();
        for(Class c:interfaces){
            System.out.println(c);
        }
        System.out.println("____________________________");

        // 獲取父類的介面
        // 先得到父類的位元組碼資訊
        Class superclass = cls.getSuperclass();
        // 獲取父類介面
        Class[] interfaces1 = superclass.getInterfaces();
        for(Class c:interfaces1){
            System.out.println(c);
        }
        System.out.println("____________________________");

        // 執行時類所在包
        Package aPackage = cls.getPackage();
        System.out.println(aPackage);
        System.out.println(aPackage.getName());
        System.out.println("____________________________");

        // 執行時類的註解
        Annotation[] annotations = cls.getAnnotations();
        for(Annotation a:annotations){
            System.out.println(a);
        }
    }
}