Java基礎篇:反射入門(上)

反射入門篇幅有點長,但我不想打散了,因爲只看其中一部分也沒啥意義,所以分爲了上中下3篇,寫的不好的方面,希望大家指出

簡介

反射能幹什麼?你只需要給我一個類的地址,我就能知道類的全部信息(類名稱、父類、繼承的接口、方法、屬性、甚至實例化並賦值),那麼下面我們就來看看它怎麼辦到的吧!

預備工作

這次我們準備用了一個Customer類,我們把它當成反射的對象,我們希望通過反射獲取它的全部信息,我們先來看看這個類吧!

  • Customer類,(包名有點隨意了):
    • (注意,下面要用)有一個無參數構造方法和一個private的構造方法
    • 爲了方便後面測試效果,實現了Person接口,但是Person接口沒有抽象方法
package com.bridge.security.util.bean;

/**
 * @創建人 zhangtaiyuan
 * @創建時間 2020/7/2 
 * @描述
 */
public class Customer implements Person{
    private String name;
    private String email;
    private int age;

    public Customer() { }

    private Customer(String name, String email, int age) {
        this.name = name;
        this.email = email;
        this.age = age;
    }

    public String getName() { return name;  }

    public void setName(String name) { this.name = name; }

    public String getEmail() { return email; }

    public void setEmail(String email) {  this.email = email;  }

    public int getAge() {  return age; }

    public void setAge(int age) {  this.age = age; }

    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}
  • 什麼也沒做的Person接口
package com.bridge.security.util.bean;
public interface Person { }

上面準備好了,我們就可以通過反射獲取Customer類信息了

獲得Class信息

獲得對象信息之前,我們必須獲得Class信息,然後從Class中獲取類對應的信息,獲取Clss有3種方法,如下:

  • 通過實體類獲得
        Customer customer = new Customer()  ; // 已經存在有指定類的實例化對象
        Class<? extends Customer> cls = customer.getClass() ;
        System.out.println(cls.getName());	//輸出結果:com.bridge.security.util.bean.Customer
  • 直接從XXX.class獲得
        Class<? extends Customer> cls = Customer.class;
        System.out.println(cls.getName());	//輸出結果:com.bridge.security.util.bean.Customer
  • 從類的路徑獲得
        Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
        System.out.println(cls.getName());//輸出結果:com.bridge.security.util.bean.Customer

上面3個方式獲得的Class都一樣,最後一個通過傳入String就能獲得Class對象,是不是讓我們想起了JDBC,哈哈

通過Class獲得各種屬性

通過Class實例化對象
  • 在JDK9之前:class.newInstance()(jDK9開始不建議使用這個方法了)
  • 在JDK9之後:clazz.getDeclaredConstructor().newInstance()
    • 大部分公司還在用jdk8,所以例子用的9之前的方式:
        Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
        Object obj = cls.newInstance() ;	// 實例化對象,JDK 9後被廢除了
        //Object obj = cls.getDeclaredConstructor().newInstance() ;  JDK 9之後才能用
        System.out.println(obj); // 由於沒有賦值:輸出的都是null 輸出結果:Customer{name='null', email='null', age='0'}
  • 看着上面,你是不是明白了,如果沒有反射,那麼工廠模式創建實現類時,就會出現很多判斷語句,並且當有新的工廠的實現類時,你就得修改代碼並且升級版本,所以,沒有反射,這種設計模式幾乎不可能實現的(維護太麻煩)
通過Class獲取屬性
  • 獲得包路徑:public Package getPackage();//比下面多一個“package”
  • 獲得包路徑:public Package getPackageName();
        Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
        System.out.println(cls.getPackage()); // package com.bridge.security.util.bean
        System.out.println(cls.getPackageName()); // com.bridge.security.util.bean
  • 獲得父類:public Class<? super T> getSuperclass()
        Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ;
        Class superclass = cls.getSuperclass();// 返回的是class
        System.out.println(superclass);// class java.lang.Object
  • 獲得接口:public Class<?>[] getInterfaces()
        Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
        for (Class<?> inter:clazz.getInterfaces()){ //獲得接口,是一個class數組
            System.out.println(inter.getName()); //com.bridge.security.util.bean.Person
        }
  • 構造方法
    • 獲取所有構造方法:public Constructor<?>[] getDeclaredConstructors()

    • 獲取指定的構造方法:public Constructor getDeclaredConstructor(Class<?>… parameterTypes)

    • 獲取所有公開的構造方法:public Constructor<?>[] getConstructors()

    • 獲取公開的指定構造方法:public Constructor getConstructor​(Class<?>… parameterTypes)

      • 全部構造方法
        Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
        for (Constructor<?> constructor:clazz.getDeclaredConstructors()){ //獲得所有構造方法,包括非公開的 Customer中有個private方法
            System.out.println(constructor.getName() + Arrays.toString(constructor.getParameterTypes())); 
        }
        /**
        * 下面是輸出結果
        * com.bridge.security.util.bean.Customer[]
        * com.bridge.security.util.bean.Customer[class java.lang.String, class java.lang.String, int]
        */
  • 指定構成方法
        Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
        System.out.println(clazz.getDeclaredConstructor().getName() + Arrays.toString(clazz.getDeclaredConstructor().getParameterTypes()));
        //下面是獲得private 的夠着方法
        System.out.println(clazz.getDeclaredConstructor(String.class,String.class,int.class).getName() + Arrays.toString(clazz.getDeclaredConstructor(String.class,String.class,int.class).getParameterTypes()));
        /**
         *  輸出結果:
         *  com.bridge.security.util.bean.Customer[]
         *  com.bridge.security.util.bean.Customer[class java.lang.String, class java.lang.String, int]
         */
  • 公開的構造方法,下面就沒有private構造方法了
        Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
        for (Constructor<?> constructor:clazz.getConstructors()){ //獲得所有構造方法,包括非公開的 Customer中有個private方法
            System.out.println(constructor.getName() + Arrays.toString(constructor.getParameterTypes()));
        }
    	/**
        * 下面是輸出結果
        * com.bridge.security.util.bean.Customer[]
        */
  • 指定的公開的構造方法,下面嘗試去獲得private的構造方法,就會直接報錯
        Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ;
        System.out.println(clazz.getConstructor().getName() + Arrays.toString(clazz.getConstructor().getParameterTypes()));
        //下面是獲得private 的夠着方法
        System.out.println(clazz.getConstructor(String.class,String.class,int.class));
        /**
         *  輸出結果:
         *  com.bridge.security.util.bean.Customer[]
         *  Exception in thread "main" java.lang.NoSuchMethodException: com.bridge.security.util.bean.Customer.<init>(java.lang.String, java.lang.String, int)
         * 	at java.base/java.lang.Class.getConstructor0(Class.java:3322)
         * 	at java.base/java.lang.Class.getConstructor(Class.java:2108)
         * 	at com.bridge.security.util.bean.TestDemo.main(TestDemo.java:16)
         */

總結

反射提供了另外一種設計思路,比如工廠模式,很多框架軟件裏都能看到它應用場景,比如:JDBC

未完…… 還有反射入門(中、下)

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