欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中反射機(jī)制的使用詳解

 更新時(shí)間:2023年09月19日 08:38:03   作者:_雨_  
這篇文章主要介紹了Java中反射機(jī)制的使用詳解,Java的發(fā)射機(jī)制允許程序在運(yùn)行時(shí)檢查和操作任意一個(gè)類、方法、屬性等的信息,包括了類名、方法名、屬性名、參數(shù)列表以及訪問修飾符等,需要的朋友可以參考下

反射的基本介紹

Java的發(fā)射機(jī)制(Reflection)是指在運(yùn)行時(shí)動(dòng)態(tài)地獲取類的信息并操作對(duì)象的能力。

Java的發(fā)射機(jī)制允許程序在運(yùn)行時(shí)檢查和操作任意一個(gè)類、方法、屬性等的信息,包括了類名、方法名、屬性名、參數(shù)列表以及訪問修飾符等。

通過Java的發(fā)射機(jī)制,可以實(shí)現(xiàn)一些高級(jí)的功能,比如動(dòng)態(tài)生成代理對(duì)象、動(dòng)態(tài)生成類、動(dòng)態(tài)配置對(duì)象等。同時(shí),Java的一些框架也廣泛應(yīng)用了發(fā)射機(jī)制,比如Spring框架中大量使用了反射機(jī)制來實(shí)現(xiàn)依賴注入和AOP等功能。

Java中一些常用的反射API包括Class、Method、Field、Constructor等。其中,Class類是反射機(jī)制的核心,通過它可以獲取一個(gè)類的所有信息。Method和Field則分別表示類中的方法和屬性,Constructor則表示類中的構(gòu)造方法。

Java的發(fā)射機(jī)制給Java編程帶來了更大的靈活性,但同時(shí)也需要注意到發(fā)射機(jī)制的運(yùn)行效率相對(duì)較低,同時(shí)也可能破壞類的封裝性,因此在使用時(shí)需要謹(jǐn)慎考慮。

在了解反射的基本介紹之后,我們?cè)趤砜纯捶瓷涞男枨?,為什么?huì)需要反射

先看一段代碼

代碼演示:

package com.reflection.question;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
 * 反射問題的引入
 */
@SuppressWarnings({"all"})
public class ReflectionQuestion {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //根據(jù)配置文件 re.properties 指定信息, 創(chuàng)建Cat對(duì)象并調(diào)用方法hi
        //傳統(tǒng)的方式 new 對(duì)象 -》 調(diào)用方法
//        Cat cat = new Cat();
//        cat.hi(); ===> cat.cry() 修改源碼.
        //我們嘗試做一做 -> 明白反射
        //1. 使用Properties 類, 可以讀寫配置文件    Properties的底層就是HashTable
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));//加載配置文件的鍵值對(duì)到properties對(duì)象
        String classfullpath = properties.get("classfullpath").toString();//"com.hspedu.Cat"  根據(jù)鍵獲取值
        String methodName = properties.get("method").toString();//"hi"
        System.out.println("classfullpath=" + classfullpath);
        System.out.println("method=" + methodName);
        //2. 創(chuàng)建對(duì)象 , 傳統(tǒng)的方法,行不通 =》 反射機(jī)制
        //new classfullpath();
        //3. 使用反射機(jī)制解決
        //(1) 加載類, 返回Class類型的對(duì)象cls
        Class cls = Class.forName(classfullpath);
        //(2) 通過 cls 得到你加載的類 com.hspedu.Cat 的對(duì)象實(shí)例
        Object o = cls.newInstance();
        System.out.println("o的運(yùn)行類型=" + o.getClass()); //運(yùn)行類型
        //(3) 通過 cls 得到你加載的類 com.hspedu.Cat 的 methodName"hi"  的方法對(duì)象
        //    即:在反射中,可以把方法視為對(duì)象(萬物皆對(duì)象)
        Method method1 = cls.getMethod(methodName);
        //(4) 通過method1 調(diào)用方法: 即通過方法對(duì)象來實(shí)現(xiàn)調(diào)用方法
        System.out.println("=============================");
        method1.invoke(o); //傳統(tǒng)方法 對(duì)象.方法() , 反射機(jī)制 方法.invoke(對(duì)象)
    }
}

反射的需求

Java反射機(jī)制的需求主要有以下幾個(gè)方面:

  1. 動(dòng)態(tài)加載類和調(diào)用類方法:通過反射機(jī)制,可以在運(yùn)行時(shí)動(dòng)態(tài)的加載一個(gè)類,并調(diào)用該類的方法。這種方式可以實(shí)現(xiàn)更加靈活的代碼編寫,避免了在編譯期就要確定所有的類和方法的限制。
  2. 實(shí)現(xiàn)通用框架:通過反射機(jī)制,可以實(shí)現(xiàn)通用的框架,比如ORM(對(duì)象-關(guān)系映射)框架、依賴注入框架、AOP(面向切面編程)框架等。這些框架需要在運(yùn)行時(shí)動(dòng)態(tài)的獲取類的信息,然后進(jìn)行相應(yīng)的操作。
  3. 修改類的屬性和方法:通過反射機(jī)制,可以在運(yùn)行時(shí)修改類的屬性和方法,從而實(shí)現(xiàn)更加靈活的代碼編寫。
  4. 實(shí)現(xiàn)序列化和反序列化:Java中的序列化和反序列化需要用到反射機(jī)制,通過反射機(jī)制可以獲取對(duì)象的屬性和方法,然后將其序列化為字節(jié)流或者反序列化為對(duì)象。
  5. 動(dòng)態(tài)代理:通過反射機(jī)制,可以實(shí)現(xiàn)動(dòng)態(tài)代理,即在運(yùn)行時(shí)生成一個(gè)代理對(duì)象,通過代理對(duì)象來調(diào)用目標(biāo)對(duì)象的方法,從而實(shí)現(xiàn)AOP等功能。

那么我們使用反射機(jī)制可以完成

1.在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類

2.在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象

3.在運(yùn)行時(shí)得到任意一個(gè)類所具有的成員變量和方法

4.在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的成員變量和方法

5.生成動(dòng)態(tài)代理

反射相關(guān)的主要類

1.java.lang.Class:代表一個(gè)類,Class對(duì)象表示某個(gè)類加載后在堆中的對(duì)象

2.java.lang.reflect.Method: 代表類的方法, Method對(duì)象表示某個(gè)類的方法

3.java.lang.reflect.Field: 代表類的成員變量,Field對(duì)象表示某個(gè)類的成員變量

4.java.lang.reflect.Constructor: 代表類的構(gòu)造方法,Constructor對(duì)象表示構(gòu)造器

代碼演示:

注意:反射和我們正常的使用方式有些不同,我們正常調(diào)用方法時(shí)對(duì)象名.方法名,但是在反射中是 方法名.對(duì)象名這里要注意一下

package com.reflection;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;
@SuppressWarnings({"all"})
public class Reflection01 {
    public static void main(String[] args) throws Exception {
        //1. 使用Properties 類, 可以讀寫配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String classfullpath = properties.get("classfullpath").toString();//"com.hspedu.Cat"
        String methodName = properties.get("method").toString();//"hi"
        //2. 使用反射機(jī)制解決
        //(1) 加載類, 返回Class類型的對(duì)象cls
        Class cls = Class.forName(classfullpath);
        //(2) 通過 cls 得到你加載的類 com.hspedu.Cat 的對(duì)象實(shí)例
        Object o = cls.newInstance();
        System.out.println("o的運(yùn)行類型=" + o.getClass()); //運(yùn)行類型
        //(3) 通過 cls 得到你加載的類 com.hspedu.Cat 的 methodName"hi"  的方法對(duì)象
        //    即:在反射中,可以把方法視為對(duì)象(萬物皆對(duì)象)
        Method method1 = cls.getMethod(methodName);
        //(4) 通過method1 調(diào)用方法: 即通過方法對(duì)象來實(shí)現(xiàn)調(diào)用方法
        System.out.println("=============================");
        method1.invoke(o); //傳統(tǒng)方法 對(duì)象.方法() , 反射機(jī)制 方法.invoke(對(duì)象)
        //java.lang.reflect.Field: 代表類的成員變量, Field對(duì)象表示某個(gè)類的成員變量
        //得到name字段
        //getField不能得到私有的屬性
        Field nameField = cls.getField("age"); //
        System.out.println(nameField.get(o)); // 傳統(tǒng)寫法 對(duì)象.成員變量 , 反射 :  成員變量對(duì)象.get(對(duì)象)
        //java.lang.reflect.Constructor: 代表類的構(gòu)造方法, Constructor對(duì)象表示構(gòu)造器
        Constructor constructor = cls.getConstructor(); //()中可以指定構(gòu)造器參數(shù)類型, 返回?zé)o參構(gòu)造器
        System.out.println(constructor);//Cat()
        Constructor constructor2 = cls.getConstructor(String.class); //這里傳入的 String.class 就是String類的Class對(duì)象
        System.out.println(constructor2);//Cat(String name)
    }
}

反射優(yōu)點(diǎn)和缺點(diǎn)

優(yōu)點(diǎn):

  • 動(dòng)態(tài)性:Java反射機(jī)制可以在運(yùn)行時(shí)動(dòng)態(tài)地獲取類的信息和操作對(duì)象,使程序更加靈活和易于擴(kuò)展。
  • 通用性:可以通過反射機(jī)制操作任意類型的對(duì)象,無需知道對(duì)象的具體類型。
  • 代碼復(fù)用性:反射機(jī)制可以讓代碼更加通用和復(fù)用,提高開發(fā)效率。
  • AOP支持:反射機(jī)制是實(shí)現(xiàn)AOP(面向切面編程)的重要手段之一。

缺點(diǎn):

  • 性能較低:Java反射機(jī)制需要在運(yùn)行時(shí)動(dòng)態(tài)地獲取對(duì)象信息和方法,需要一定的時(shí)間開銷,因此性能較低。
  • 安全問題:反射機(jī)制可以操作任意類型的對(duì)象,容易造成安全問題,需要謹(jǐn)慎使用,并在必要時(shí)進(jìn)行安全檢查。
  • 可讀性下降:由于反射機(jī)制支持動(dòng)態(tài)的獲取和操作對(duì)象,因此代碼的可讀性會(huì)下降一些,需要謹(jǐn)慎使用。
  • 不利于編譯器優(yōu)化:由于反射機(jī)制需要在運(yùn)行時(shí)動(dòng)態(tài)獲取對(duì)象信息和方法,因此編譯器很難對(duì)代碼進(jìn)行優(yōu)化。

代碼演示;

在下面的代碼中 ,我們分別測(cè)試了,使用正常的方式去調(diào)用方法,和使用反射的方式去調(diào)用方法,并且在執(zhí)行方法開始之前記錄了開始時(shí)間,在方法執(zhí)行結(jié)束之后,記錄了結(jié)束時(shí)間,最后兩個(gè)相減,就可以得到方法的執(zhí)行時(shí)間,我們就可以看出,使用正常的方式去調(diào)用方法,和使用反射的方式去調(diào)用方法,的區(qū)別。

package com.reflection;
import com.Cat;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
 * 測(cè)試反射調(diào)用a的性能,和優(yōu)化方案
 */
public class Reflection02 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //Field
        //Method
        //Constructor
        m1();
        m2();
        m3();
    }
    //傳統(tǒng)方法來調(diào)用hi
    public static void m1() {
        Cat cat = new Cat();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 90; i++) {
            cat.hi();
        }
        long end = System.currentTimeMillis();
        System.out.println("m1() 耗時(shí)=" + (end - start));
    }
    //反射機(jī)制調(diào)用方法hi
    public static void m2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class cls = Class.forName("com.Cat");
        Object o = cls.newInstance();
        Method hi = cls.getMethod("hi");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 900000000; i++) {
            hi.invoke(o);//反射調(diào)用方法
        }
        long end = System.currentTimeMillis();
        System.out.println("m2() 耗時(shí)=" + (end - start));
    }
    //反射調(diào)用優(yōu)化 + 關(guān)閉訪問檢查
    public static void m3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class cls = Class.forName("com.Cat");
        Object o = cls.newInstance();
        Method hi = cls.getMethod("hi");
        hi.setAccessible(true);//在反射調(diào)用方法時(shí),取消訪問檢查
        long start = System.currentTimeMillis();
        for (int i = 0; i < 900000000; i++) {
            hi.invoke(o);//反射調(diào)用方法
        }
        long end = System.currentTimeMillis();
        System.out.println("m3() 耗時(shí)=" + (end - start));
    }
}

反射調(diào)用優(yōu)化

Java中反射調(diào)用通常比直接調(diào)用方法緩慢,因?yàn)樗枰M(jìn)行額外的動(dòng)態(tài)類型檢查和查找。為了優(yōu)化反射調(diào)用,可以采用以下幾種方法:

緩存Method對(duì)象:通過緩存Method對(duì)象,避免動(dòng)態(tài)查找,提高調(diào)用效率。

使用方法句柄(MethodHandle):方法句柄是一種更高效的調(diào)用機(jī)制,它可以繞過反射調(diào)用的開銷。方法句柄比反射調(diào)用更快,特別是在熱代碼路徑上。

使用invokedynamic指令:為了提高反射調(diào)用的性能,Java 7引入了invokedynamic指令。它允許動(dòng)態(tài)綁定方法調(diào)用,避免了反射調(diào)用的開銷。

使用字節(jié)碼生成庫(kù):字節(jié)碼生成庫(kù)可以生成字節(jié)碼,從而避免了反射調(diào)用的開銷。比如,cglib是一個(gè)非常常用的字節(jié)碼生成庫(kù)。

到此這篇關(guān)于Java中反射機(jī)制的使用詳解的文章就介紹到這了,更多相關(guān)Java反射機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源切換的方法總結(jié)

    Spring實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源切換的方法總結(jié)

    這篇文章主要為大家詳細(xì)介紹了一種Spring實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源切換的方法,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-06-06
  • Jpa使用Page和Pageable分頁遇到的問題及解決

    Jpa使用Page和Pageable分頁遇到的問題及解決

    這篇文章主要介紹了Jpa使用Page和Pageable分頁遇到的問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Springboot的yml配置文件用法

    Springboot的yml配置文件用法

    這篇文章主要介紹了Springboot的yml配置文件用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java中常見的4種限流算法詳解

    Java中常見的4種限流算法詳解

    這篇文章主要介紹了Java中常見的4種限流算法詳解,FixedWindowRateLimiter 類表示一個(gè)固定窗口限流器,使用 limit 和 interval 參數(shù)分別表示限制請(qǐng)求數(shù)量和時(shí)間間隔,缺點(diǎn)是短時(shí)間內(nèi)可能會(huì)流量翻倍,需要的朋友可以參考下
    2023-12-12
  • SpringBoot中調(diào)用通用URL的實(shí)現(xiàn)

    SpringBoot中調(diào)用通用URL的實(shí)現(xiàn)

    在 Spring Boot 應(yīng)用程序中,有時(shí)候我們需要調(diào)用一些通用的 URL 接口,本文主要介紹了SpringBoot中調(diào)用通用URL的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Java 多線程實(shí)例詳解(二)

    Java 多線程實(shí)例詳解(二)

    本文主要介紹Java 多線程的資料整理,這里整理了詳細(xì)資料及相關(guān)示例代碼,有興趣的小伙伴可以參考下
    2016-09-09
  • spring事物傳播propagation類別含義詳解

    spring事物傳播propagation類別含義詳解

    這篇文章主要介紹了spring事物傳播propagation類別含義詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • 詳解Java并發(fā)編程之原子類

    詳解Java并發(fā)編程之原子類

    這篇文章主要為大家介紹了Java并發(fā)編程之原子類介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 實(shí)例講解Java設(shè)計(jì)模式編程中如何運(yùn)用代理模式

    實(shí)例講解Java設(shè)計(jì)模式編程中如何運(yùn)用代理模式

    這篇文章主要介紹了Java設(shè)計(jì)模式編程中如何運(yùn)用代理模式,文中舉了普通代理和強(qiáng)制代理的例子作為代理模式的擴(kuò)展內(nèi)容,需要的朋友可以參考下
    2016-02-02
  • 關(guān)于java String中intern的深入講解

    關(guān)于java String中intern的深入講解

    這篇文章主要給大家介紹了關(guān)于java String中intern的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評(píng)論