java反射學(xué)習(xí)

反射的核心Class類

Class<T>類是一個(gè)特殊的類,不能手動(dòng)創(chuàng)建,只能由jvm來(lái)創(chuàng)建。 jvm在類加載時(shí)會(huì)為每個(gè)類生成一個(gè)與之對(duì)應(yīng)的Class<類>對(duì)象在Java堆中(且每個(gè)類只會(huì)有一個(gè)對(duì)應(yīng)的Class<類>對(duì)象),用來(lái)保存該類的結(jié)構(gòu)信息。該類的對(duì)象都要通過(guò)這個(gè)Class<類>對(duì)象來(lái)進(jìn)行實(shí)例化。

可以通過(guò)Class的對(duì)象來(lái)獲得該類的結(jié)構(gòu)信息(構(gòu)造器、方法、屬性等)。

反射是什么

JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)實(shí)體類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意方法和屬性;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱為java語(yǔ)言的反射機(jī)制。

Class<類>對(duì)象就像是一面鏡子,我們并不能直接得到加載的類里的內(nèi)容,而是需要通過(guò)Class<類>對(duì)象這面鏡子反射內(nèi)部的信息來(lái)得到的。

通過(guò)Class<類>對(duì)象來(lái)獲得類的結(jié)構(gòu)信息并且把各個(gè)結(jié)構(gòu)部分分別映射成各個(gè)對(duì)象這個(gè)過(guò)程就是反射了。

如何獲得Class<類>對(duì)象

創(chuàng)建一個(gè)User類來(lái)進(jìn)行測(cè)試

package com.rainc.test.bean;

/**
 * @Author rainc
 * @create 2019/10/12 19:51
 */
public class User {
    private int id;
    private int age;
    private String name;

    public User() {
    }

    public User(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
    public static void main(String[] args) {
        User user=new User();
        //1.通過(guò)該類的對(duì)象直接過(guò)得Class對(duì)象
        Class clz=user.getClass();
        System.out.println(clz);
        //2.通過(guò)類.class獲得
        clz=User.class;
        System.out.println(clz);
        //3.調(diào)用Class的靜態(tài)方法forName通過(guò)類全名來(lái)獲得
        try {
            String path = "com.rainc.test.bean.User";
            clz = Class.forName(path);
            System.out.println(clz);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
Snipaste_2019-10-19_16-43-41.png

通過(guò)反射api來(lái)獲得類的結(jié)構(gòu)信息

  public static void main(String[] args) {
        String path = "com.rainc.test.bean.User";
        try {
            Class clz = Class.forName(path);
            //獲取類的名字
            System.out.println(clz.getName());//獲得類全名
            System.out.println(clz.getSimpleName());//獲得類名
            //獲取屬性信息
            Field[] fields = clz.getFields();//只能獲得public的field
            for (Field temp : fields) {
                System.out.println("屬性:" + temp);
            }
            fields = clz.getDeclaredFields();//獲得所有的field
            for (Field temp : fields) {
                System.out.println("屬性:" + temp);
            }
            //獲得指定的屬性信息
            Field f = clz.getDeclaredField("name");

            //獲取方法信息
            Method[] methods = clz.getDeclaredMethods();
            //通過(guò)名字獲取指定的方法信息
            //獲得無(wú)參的指定方法
            for (Method temp : methods) {
                System.out.println("方法:" + temp);
            }
            Method m1 = clz.getDeclaredMethod("getName");
            //獲得有參的指定方法
            Method m2 = clz.getDeclaredMethod("setName", String.class);


            //獲得構(gòu)造器信息
            Constructor[] constructors = clz.getDeclaredConstructors();
            //獲得無(wú)參的構(gòu)造器
            Constructor c = clz.getDeclaredConstructor();
            //獲得有參的構(gòu)造器
            c = clz.getDeclaredConstructor(int.class, int.class, String.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
Snipaste_2019-10-20_09-33-17.png

通過(guò)反射api動(dòng)態(tài)的操作構(gòu)造器、方法、屬性

    public static void main(String[] args) {
        String path = "com.rainc.test.bean.User";
        try {
            Class<User> clz = (Class<User>) Class.forName(path);
            //獲得構(gòu)造器信息
            //通過(guò)反射api調(diào)用構(gòu)造方法,構(gòu)造對(duì)象
            clz.getDeclaredConstructor().newInstance();

            //通過(guò)反射api調(diào)用普通方法
            User u = clz.getDeclaredConstructor().newInstance();
            Method method = clz.getDeclaredMethod("setName", String.class);
            method.invoke(u, "rainc");//相當(dāng)于  u.setName("rainc")
            System.out.println(u.getName());

            //通過(guò)反射api操作屬性
            User u2 = clz.getDeclaredConstructor().newInstance();
            Field f = clz.getDeclaredField("name");
            f.setAccessible(true);//解除安全檢查,可以通過(guò)這個(gè)方法使用私有方法和屬性等
            f.set(u2, "rainc2");
            System.out.println(u2.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
Snipaste_2019-10-20_09-36-19.png

反射的效率

使用反射的效率會(huì)比直接通過(guò)對(duì)象調(diào)用方法效率低。通過(guò)setAccessible(true)方法解除安全檢查可以提高反射的運(yùn)行效率

創(chuàng)建TestBean類用來(lái)測(cè)試

/**
 * @Author rainc
 * @create 2019/10/20 9:19
 */
public class TestBean {
    long sum=0;

    public long getSum() {
        return sum;
    }

    public void setSum(int sum) {
        this.sum+=sum;
    }
}

創(chuàng)建Test類進(jìn)行測(cè)試

import java.lang.reflect.Method;

/**
 * @Author rainc
 * @create 2019/10/20 9:19
 */
public class TestAccessiable {
    public static void main(String[] args) throws Exception {
        test01();
        test02();
        test03();

    }

    /**
     * 普通方法
     */
    public static void test01() {
       TestBean t=new TestBean();
        long startTtime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000L; i++) {
          t.setSum(i);
        }
        System.out.println("和:"+t.getSum());
        long endTime = System.currentTimeMillis();
        System.out.println("普通方法調(diào)用10億次耗時(shí):" + (endTime - startTtime) + "ms");
    }
    /**
     * 反射調(diào)用
     */
    public static void test02() throws Exception {
        TestBean t=new TestBean();
        Class clz=t.getClass();
        Method m=clz.getDeclaredMethod("setSum", int.class);
        long startTtime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000L; i++) {
            m.invoke(t,i);
        }
        System.out.println("和:"+t.getSum());
        long endTime = System.currentTimeMillis();
        System.out.println("反射調(diào)用10億次耗時(shí):" + (endTime - startTtime) + "ms");
    }
    /**
     * 解除安全檢查,反射調(diào)用
     */
    public static void test03() throws Exception {
        TestBean t=new TestBean();
        Class clz=t.getClass();
        Method m=clz.getDeclaredMethod("setSum", int.class);
        m.setAccessible(true);
        long startTtime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000L; i++) {
            m.invoke(t,i);
        }
        System.out.println("和:"+t.getSum());
        long endTime = System.currentTimeMillis();
        System.out.println("解除安全檢查,反射調(diào)用10億次耗時(shí):" + (endTime - startTtime) + "ms");
    }
}

Snipaste_2019-10-20_09-43-18.png

可以看出,普通的方法調(diào)用效率最高,其次是解除安全檢查的,效率最低的是直接通過(guò)反射調(diào)用。

盡管反射的效率并不如普通的方法調(diào)用,但是由于其擁有動(dòng)態(tài)性,在框架中有著大量的使用,而這些框架卻能大大的提高我們的工作效率。因此犧牲一定的性能效率來(lái)提高工作效率也是必要的。

反射操作泛型

  • ParameterizedType:表示一種參數(shù)化的類型,比如Collection< String >(常用)
  • GenericArrayType:表示一種元素類型是參數(shù)化類型或者類型變量的數(shù)組類型
  • TypeVariable:是各種類型變量的公共父接口
  • WildcardType:代表一種通配符類型表達(dá)式,比如?、? extends Number、? super Integer。(wildcard是一個(gè)單詞:就是”通配符“)
import com.rainc.test.bean.User;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * @Author rainc
 * @create 2019/10/20 10:10
 */
public class TestGenericity {
    public void test01(Map<String, User> map, List<User> list){
    }
    public Map<Integer, User>  test02(){
        return null;
    }
    public static void main(String[] args) throws Exception {
    Class clz=TestGenericity.class;
    //獲得指定方法的泛型
        System.out.println("獲得指定方法的泛型");
        Method m=clz.getMethod("test01", Map.class, List.class);
        //取得方法的所有參數(shù)類型
        Type[] t=m.getGenericParameterTypes();
        for (Type paramType:t){
            System.out.println("#"+paramType);
            //判斷取得的參數(shù)是否為參數(shù)化類型
            if (paramType instanceof ParameterizedType){
                //是的話將其強(qiáng)制轉(zhuǎn)型并獲得泛型的真正類型
                Type[] genericTypes=((ParameterizedType) paramType).getActualTypeArguments();
                for (Type genericType:genericTypes){
                    System.out.println("泛型類型:"+genericType);
                }
            }
        }

        //獲得指定方法返回值泛型
        System.out.println("\n\n指定方法返回值泛型");
        Method m2=clz.getMethod("test02");
        //由于返回值只會(huì)有一個(gè)因此不需要數(shù)組
        Type returnType =m2.getGenericReturnType();
        if (returnType instanceof ParameterizedType){
            Type[] genericTypes=((ParameterizedType) returnType).getActualTypeArguments();
            for (Type genericType:genericTypes){
                System.out.println("泛型類型:"+genericType);
            }
        }
    }
}

Snipaste_2019-10-20_10-47-16.png

參考: https://www.bilibili.com/video/av30023103/?p=275
個(gè)人博客: https://www.rainc.top/2019/10/19/java-study/reflection-study/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容