如何使用 Java 反射?反射的用法及案例

簡介

    Java Reflection,稱爲 Java 反射,是Java基礎部分的一個比較難的點。Reflection(反射)是被視爲動態語言的關鍵,通過反射機制,我們可以在運行時(runtime)獲取類的完整結構。例如,可以獲取到類的變量名、方法、構造器、內部類、接口、註解等等,並且通過反射機制可以對類內部進行操作。

    Java反射機制在實際開發中是非常常用的,強大一詞完全可以用來形容它。作爲Java基礎內容的一部分,並且在很多開源框架(jdbc、spring、hibermate...)都使用到反射,可謂反射的重要性。

例子

首先,定義一個 Person 類及 Student 類,Student 繼承自 Person 類,代碼非常簡單。如下:

    package com.test;
     
    public class Person<T> {
     
        public String weight;
        public String height;
     
        public Person() {
            super();
        }
     
        public Person(String weight, String height) {
            super();
            this.weight = weight;
            this.height = height;
        }
     
        public String getWeight() {
            return weight;
        }
     
        public void setWeight(String weight) {
            this.weight = weight;
        }
     
        public String getHeight() {
            return height;
        }
     
        public void setHeight(String height) {
            this.height = height;
        }
     
        @Override
        public String toString() {
            return "Person [weight=" + weight + ", height=" + height + "]";
        }
     
    }

    package com.test;
     
    import java.io.Serializable;
     
    public class Student extends Person<String> implements Serializable, Runnable {
     
        public String stuNo;
        private String stuName;
     
        public Student() {
            super();
        }
     
        public Student(String stuNo, String stuName) {
            super();
            this.stuNo = stuNo;
            this.stuName = stuName;
        }
     
        public String getStuNo() {
            return stuNo;
        }
     
        public void setStuNo(String stuNo) {
            this.stuNo = stuNo;
        }
     
        public String getStuName() {
            return stuName;
        }
     
        public void setStuName(String stuName) {
            this.stuName = stuName;
        }
     
        private int exam(String str, Integer tag) throws NoSuchMethodException {
            System.out.println(str);
            return tag;
        }
     
        @Override
        public String toString() {
            return "Student [stuNo=" + stuNo + ", stuName=" + stuName + "]";
        }
     
        @Override
        public void run() {
     
        }
    }

有了這兩個類,我們就可以開始利用反射來獲取類的內部結構了。我們常規的創建對象操作:

     
        @Test
        public void test() {
            Student student = new Student();
            student.setStuNo("01");
            student.setStuName("張三");
        }

    反射4種方式

在開始之前,我們來學習如何利用反射的方式來獲取類的結構,反射的方式有這樣 4 種。

    * 反射的4種獲取方式,反射的源頭就是獲取到一個 Class 對象進行操作類的內部方法和獲取類的結構。

      注意:父類中聲明爲 public 的變量、方法、接口等也可以被獲取到。

        @Test
        public void test() throws Exception {
            /** 第一種反射方式 */
            Class clazz1 = new Student().getClass();
     
            /** 第二種反射方式 */
            Class clazz2 = Student.class;
     
            /** 第三種反射方式 */
            // 先聲明 xxx 類所在包的完整名
            String className = "com.test.Student";
            Class clazz3 = Class.forName(className);
     
            /** 第四種反射方式 */
            Class clazz4 = this.getClass().getClassLoader().loadClass(className);
        }

以下都是利用反射來獲取類結構的例子。

    獲取類中的變量,並進行賦值

        @Test
        public void test() throws Exception {
            Class clazz = Student.class;
            Student student = (Student) clazz.newInstance();
            /** 聲明爲 public 類型的變量可以這樣獲取 **/
            Field field1 = clazz.getField("stuNo");
            field1.set(student, "01");
            System.out.println(student);
            /** 其他類型變量只能通過如下獲取 **/
            Field field2 = clazz.getDeclaredField("stuName");
            field2.setAccessible(true);
            field2.set(student, "張三");
            System.out.println(student);
        }

    獲取變量的權限修飾符(private、protected、public)

        @Test
        public void test() throws Exception {
            Class clazz = Student.class;
            Student student = (Student) clazz.newInstance();
            Field field1 = clazz.getField("stuNo");
            Field field2 = clazz.getDeclaredField("stuName");
        
            /** 獲取 權限修飾符 **/
            String str = Modifier.toString(field1.getModifiers());
            System.out.println(str);
            String str2 = Modifier.toString(field2.getModifiers());
            System.out.println(str2);
        }

    獲取類中的方法,並調用該方法(需注意權限修飾符)

    獲取類中方法的返回值

    獲取類中方法形參列表

    獲取類中方法異常類型

        @Test
        public void test() throws Exception {
            Class clazz = Student.class;
            Student student = (Student) clazz.newInstance();
        
            Method method = clazz.getMethod("setStuNo", String.class);
            method.invoke(student, "02");
            System.out.println(student);
            /** 獲取方法的返回值類型 */
            Class returnType = method.getReturnType();
            System.out.println(returnType);
     
            Method method2 = clazz.getDeclaredMethod("exam", String.class, Integer.class);
            method2.setAccessible(true);
            method2.invoke(student, "invoke exam method", 1);
            /** 獲取方法的形參列表 */
            Class[] params = method2.getParameterTypes();
            for (Class param : params) {
                System.out.println(param);
            }
            /** 獲取方法的異常類型 */
            Class[] exceptions =method2.getExceptionTypes();
            for(Class excp : exceptions) {
                System.out.println(excp);
            }
        }

    獲取類的完整包名、

    類中所有的構造器、

    類中實現的所有接口

        @Test
        public void test() throws Exception {
            Class clazz = Student.class;
            Student student = (Student) clazz.newInstance();
            //獲取包名
            System.out.println(clazz.getPackage());
            /**
             * 獲取 所有構造器
             */
            Constructor[] constructor = clazz.getDeclaredConstructors();
            for(Constructor cons : constructor) {
                System.out.println(cons);
            }
            /**
             * 獲取 所有接口
             */
            Class[] interfaces =clazz.getInterfaces();
            for( Class its:interfaces) {
                System.out.println(its);
            }
        }

    獲取父類的結構

        @Test
        public void test() throws Exception {
            Class clazz = Student.class;
            Student student = (Student) clazz.newInstance();
            //獲取父類
            System.out.println(clazz.getSuperclass());
            //獲取帶泛型的父類
            Type type = clazz.getGenericSuperclass();
            System.out.println(type);
            
            /**
             * 獲取父類的泛型
             */
            Type type2 = clazz.getGenericSuperclass();
            ParameterizedType args = (ParameterizedType)type2;
            Type[] types = args.getActualTypeArguments();
            String t_Type = (String)types[0].getTypeName();
            System.out.println(t_Type);
        }

  以上的幾個例子可以讓我們知道反射的作用,反射能夠在運行時狀態下獲取類的完整結構,在框架裏顯得尤爲重要。

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