最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java反射和動(dòng)態(tài)代理的使用解讀

 更新時(shí)間:2025年02月07日 15:36:27   作者:空說(shuō)  
這篇文章主要介紹了Java反射和動(dòng)態(tài)代理的概念、使用方法和應(yīng)用場(chǎng)景,反射允許在運(yùn)行時(shí)動(dòng)態(tài)地獲取類(lèi)的信息和調(diào)用類(lèi)的方法,而動(dòng)態(tài)代理則可以在不修改原有代碼的情況下,為方法調(diào)用添加額外的功能

1、反射

1.1 反射的概述

是在運(yùn)行狀態(tài)中,不用創(chuàng)建對(duì)象就能夠調(diào)用任意一個(gè)類(lèi)的所有屬性和方法;

1.2 反射作用

反射都是從class字節(jié)碼文件中獲取的內(nèi)容。

  • 獲取class字節(jié)碼文件的對(duì)象
  • 利用反射如何獲取構(gòu)造方法(創(chuàng)建對(duì)象)
  • 利用反射如何獲取成員變量(賦值,獲取值)
  • 利用反射如何獲取成員方法(運(yùn)行)

1.3 獲取字節(jié)碼文件對(duì)象的方式

  • Class這個(gè)類(lèi)里面的靜態(tài)方法forName(“全類(lèi)名”)(最常用)
  • 通過(guò)class屬性獲取,一般更多的是當(dāng)做參數(shù)進(jìn)行傳遞
  • 通過(guò)對(duì)象獲取字節(jié)碼文件對(duì)象,當(dāng)我們已經(jīng)有了這個(gè)類(lèi)的對(duì)象時(shí),才可以使用。
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //1. 第一種方式
        //全類(lèi)名 : 包名 + 類(lèi)名
        Class clazz1 = Class.forName("com.ya.reflect.demo01.Student");

        //2. 第二種方式
        Class clazz2 = Student.class;

        //3.第三種方式
        Student s = new Student();
        Class clazz3 = s.getClass();

        System.out.println(clazz1 == clazz2);
        System.out.println(clazz2 == clazz3);
    }
}

1.4 字節(jié)碼文件和字節(jié)碼文件對(duì)象

  • java文件(源代碼階段):就是編寫(xiě)的java代碼。
  • 字節(jié)碼文件(加載階段):就是通過(guò)java文件編譯之后的class文件(是在硬盤(pán)上真實(shí)存在的,用眼睛能看到的)
  • 字節(jié)碼文件對(duì)象(運(yùn)行階段):當(dāng)class文件加載到內(nèi)存之后,虛擬機(jī)自動(dòng)創(chuàng)建出來(lái)的對(duì)象。這個(gè)對(duì)象里面至少包含了:構(gòu)造方法,成員變量,成員方法。

反射獲取的是字節(jié)碼文件對(duì)象,這個(gè)對(duì)象在內(nèi)存中是唯一的。

1.5 獲取構(gòu)造方法

規(guī)則:

  • get表示獲取
  • Declared表示私有
  • 最后的s表示所有,復(fù)數(shù)形式
  • 如果當(dāng)前獲取到的是私有的,必須要臨時(shí)修改訪(fǎng)問(wèn)權(quán)限setAccessible(true),否則無(wú)法使用
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {

        //1.獲取class字節(jié)碼文件對(duì)象
        Class clazz = Class.forName("com.ya.reflect.demo02.Student");

        //2.獲取構(gòu)造方法
        // 2.1 返回所有公共構(gòu)造方法對(duì)象的數(shù)組
        System.out.println("-----返回所有公共構(gòu)造方法對(duì)象的數(shù)組----");
        Constructor[] con1 = clazz.getConstructors();
        for (Constructor con : con1) {
            System.out.println(con);
        }

        // 2.2 返回所有構(gòu)造方法對(duì)象的數(shù)組
        System.out.println("-------返回所有構(gòu)造方法對(duì)象的數(shù)組------");
        Constructor[] con2 = clazz.getDeclaredConstructors();
        for (Constructor con : con2) {
            System.out.println(con);

        }

        // 2.3 返回所有構(gòu)造方法對(duì)象的數(shù)組
        System.out.println("-------返回單個(gè)公共構(gòu)造方法對(duì)象------");
        Constructor con3 = clazz.getConstructor(String.class);
        System.out.println(con3);
        //2.4 獲取指定的空參構(gòu)造
        System.out.println("-------獲取指定的空參構(gòu)造------");
        Constructor con4 = clazz.getConstructor();
        System.out.println(con4);


        // 2.5 返回所有構(gòu)造方法對(duì)象的數(shù)組
        System.out.println("-------返回單個(gè)構(gòu)造方法對(duì)象------");
        Constructor con5 = clazz.getDeclaredConstructor(String.class,int.class);
        System.out.println(con5);


        System.out.println("-----獲取構(gòu)造方法的權(quán)限修飾符(返回整數(shù))--------");
        // 返回的是整數(shù),public 1,private 2,protected 4,abstract 1024
        int modifiers = con5.getModifiers();
        System.out.println(modifiers);

        System.out.println("-----獲取構(gòu)造方法的參數(shù)--------");
        Parameter[] parameters = con5.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        System.out.println("--------創(chuàng)建對(duì)象-----------");
        //暴力反射:表示臨時(shí)取消權(quán)限校驗(yàn)
        con5.setAccessible(true);   // 如果這個(gè)權(quán)限修飾符是私有的,就要取消權(quán)限校驗(yàn)
        Student stu = (Student) con5.newInstance("張三", 23);
        System.out.println(stu);
    }
}

1.6 獲取構(gòu)造方法并創(chuàng)建對(duì)象

public class ReflectDemo02 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        
        //需求1:獲取空參,并創(chuàng)建對(duì)象(所創(chuàng)建的對(duì)象的屬性是默認(rèn)值)
        //1.獲取整體的字節(jié)碼文件對(duì)象
        Class clazz = Class.forName("com.ya.reflect.demo02.Student");
        //2.獲取空參的構(gòu)造方法
        Constructor con = clazz.getConstructor();
        //3.利用空參構(gòu)造方法創(chuàng)建對(duì)象
        Student stu = (Student) con.newInstance();
        System.out.println(stu);

        System.out.println("----------------------------------");

        //需求2:獲取帶參構(gòu)造,并創(chuàng)建對(duì)象
        //1.獲取整體的字節(jié)碼文件對(duì)象
        Class clazz2 = Class.forName("com.ya.reflect.demo02.Student");
        //2.獲取有參構(gòu)造方法
        Constructor con2 = clazz2.getDeclaredConstructor(String.class, int.class);
        //3.臨時(shí)修改構(gòu)造方法的訪(fǎng)問(wèn)權(quán)限(暴力反射)
        con2.setAccessible(true);
        //4.直接創(chuàng)建對(duì)象
        Student stu2 = (Student) con2.newInstance("zhangsan", 23);
        System.out.println(stu2);
    }
}

1.7 獲取成員變量并獲取值和修改值

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //1.獲取class字節(jié)碼文件的對(duì)象
        Class clazz = Class.forName("com.ya.reflect.demo03.Student");
        //2.獲取所有的成員變量
        System.out.println("-----獲取所有的成員變量----");
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        //3.獲取單個(gè)的成員變量
        System.out.println("-----獲取單個(gè)的成員變量----");
        Field fieldName = clazz.getDeclaredField("name");
        System.out.println(fieldName);
        System.out.println("-----獲取成員變量的數(shù)據(jù)類(lèi)型----");
        Class<?> type = fieldName.getType();
        System.out.println(type);
        System.out.println("-----獲取成員變量記錄的值----");
        Student student = new Student("zhangsan", 23, "男");
        fieldName.setAccessible(true);
        String value = (String) fieldName.get(student);
        System.out.println(value);
        System.out.println("-----修改對(duì)象里面記錄的值---");
        fieldName.set(student,"lisi");
        System.out.println(student);
    }
}

1.8 獲取成員方法

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
       
        //1. 獲取class字節(jié)碼文件對(duì)象
        Class clazz = Class.forName("com.ya.reflect.demo04.Student");

        //2. 獲取里面所有的方法對(duì)象(包含父類(lèi)中所有的公共方法)
        System.out.println("-------獲取里面所有的方法對(duì)象(包含父類(lèi)中所有的公共方法)-----");
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        // 3. 獲取里面所有的方法對(duì)象(不能獲取父類(lèi)的,但是可以獲取本類(lèi)中私有的方法)
        System.out.println("--獲取里面所有的方法對(duì)象(不能獲取父類(lèi)的,但是可以獲取本類(lèi)中私有的方法)--");
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
        // 4.獲取指定的單一方法
        System.out.println("-------獲取指定的單一方法-----");
        Method eatMethod = clazz.getDeclaredMethod("eat", String.class);
        System.out.println(eatMethod);

        // 5.獲取方法的修飾符(返回整數(shù))
        System.out.println("-------獲取方法的修飾符(返回整數(shù))-----");
        int modifiers = eatMethod.getModifiers();
        System.out.println(modifiers);

        // 6.獲取方法的名字
        System.out.println("-------獲取方法的名字-----");
        String eatMethodName = eatMethod.getName();
        System.out.println(eatMethodName);

        // 7.獲取方法的形參
        System.out.println("-------獲取方法的形參-----");
        Parameter[] parameters = eatMethod.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        //8.獲取方法的拋出的異常
        System.out.println("-------獲取方法的拋出的異常-----");
        Class[] exceptionTypes = eatMethod.getExceptionTypes();
        for (Class exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }
    }
}

1.9 獲取成員方法并運(yùn)行

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1. 獲取class字節(jié)碼文件對(duì)象
        Class clazz = Class.forName("com.ya.reflect.demo04.Student");
        //2. 獲取指定的單一方法
        Method eatMethod = clazz.getDeclaredMethod("eat", String.class); 
        // 3. 方法運(yùn)行
        System.out.println("-------方法運(yùn)行-----");
        Student student = new Student();
        eatMethod.setAccessible(true);
        String result = (String) eatMethod.invoke(student, "漢堡包");
        System.out.println(result);
    }
}

2. 動(dòng)態(tài)代理

2.1 動(dòng)態(tài)代理好處

  • 無(wú)侵入式的給方法增強(qiáng)功能。
  • 調(diào)用者(BitStar)–>代理(ProxyUtil)–>對(duì)象(Star)

2.2 動(dòng)態(tài)代理三要素

  • 接口:代理對(duì)象,被代理類(lèi)和代理類(lèi)都需要實(shí)現(xiàn)這個(gè)接口(本例是Star)
  • 代理類(lèi):通過(guò)Proxy類(lèi)動(dòng)態(tài)生成的代理類(lèi)(本例是ProxyUtil)
  • 被代理類(lèi):代理類(lèi)實(shí)例,它會(huì)代替被代理對(duì)象處理方法調(diào)用(本例是BigStar)

注:代理可以增強(qiáng)或者攔截的方法都在接口中,接口需要寫(xiě)在newProxyInstance的第二個(gè)參數(shù)里。

2.3 動(dòng)態(tài)代理簡(jiǎn)單實(shí)現(xiàn)

//代理對(duì)象
public interface Star {
	//可以把所有想要被代理的方法定義在接口當(dāng)中
    //唱歌
    public abstract String sing(String name);
    //跳舞
    public abstract void dance();
}
//被代理類(lèi)
public class BigStar implements Star{
    private String name;

    public BigStar() {
    }
    public BigStar(String name) {
        this.name = name;
    }
    //唱歌
    @Override
    public String sing(String name){
        System.out.println(this.name + "正在唱" + name);
        return "謝謝";
    }
    //跳舞
    @Override
    public void dance(){
        System.out.println(this.name + "正在跳舞");
    }
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String toString() {
        return "BigStar{name = " + name + "}";
    }
}


//代理類(lèi)
// 創(chuàng)建代理   java.lang.reflect.Proxy類(lèi):提供了為對(duì)象產(chǎn)生代理對(duì)象的方法
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
參數(shù)一:用于指定用哪個(gè)類(lèi)加載器,去加載生成的代理類(lèi)
參數(shù)二:指定接口,這些接口用于指定生成的代理有哪些方法
參數(shù)三:用來(lái)指定生成的代理對(duì)象要干什么事情
   
public class ProxyUtil {

    /**
     *  形參:被代理的明星對(duì)象
     *  返回值:給明星創(chuàng)建的代理
     */
    public static Star createProxy(BigStar bigStar){
        // 創(chuàng)建代理
        // 這個(gè)代碼沒(méi)有顯示實(shí)現(xiàn)Star接口,但通過(guò) JDK動(dòng)態(tài)代理機(jī)制 隱式地為生成的代理類(lèi)添加了Star接口的實(shí)現(xiàn),從而可以看作實(shí)現(xiàn)了Star接口
        Star star = (Star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),//參數(shù)一:用于指定用哪個(gè)類(lèi)加載器,去加載生成的代理類(lèi)
                new Class[]{Star.class},//參數(shù)二:指定接口,這些接口用于指定生成的代理有哪些方法
                new InvocationHandler() {	//參數(shù)三:用來(lái)指定生成的代理對(duì)象要干什么事情
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /**
                         * 參數(shù)一:代理的對(duì)象,即star變量引用的對(duì)象
                         * 參數(shù)二:要運(yùn)行的方法,sing,dance
                         * 參數(shù)三:調(diào)用sing方法時(shí),傳遞的實(shí)參
                         */
                        if("sing".equals(method.getName())){
                            System.out.println("準(zhǔn)備話(huà)筒,收錢(qián)");
                        }else if("dance".equals(method.getName())){
                            System.out.println("準(zhǔn)備場(chǎng)地,收錢(qián)");
                        }
                        //去找大明星開(kāi)始唱歌或者跳舞
                        //代碼的表現(xiàn)形式:調(diào)用大明星里面唱歌或者跳舞的方法
                        return method.invoke(bigStar,args);
                    }
                }
        );
        return star;
    }
}

//代理測(cè)試
public class Test {
    public static void main(String[] args) {
        //1. 獲取代理的對(duì)象
        BigStar bigStar = new BigStar("機(jī)哥");
        Star proxy = ProxyUtil.createProxy(bigStar);

        //2. 調(diào)用唱歌的方法
        String result = proxy.sing("只因你太美");
        System.out.println(result);
    }
}

2.4 動(dòng)態(tài)代理擴(kuò)展

動(dòng)態(tài)代理,還可以攔截方法。比如:在這個(gè)故事中,經(jīng)紀(jì)人作為代理,如果別人讓邀請(qǐng)大明星去唱歌,打籃球,經(jīng)紀(jì)人就增強(qiáng)功能。但是如果別人讓大明星去掃廁所,經(jīng)紀(jì)人就要攔截,不會(huì)去調(diào)用大明星的方法。

public class ProxyUtil {
    public static Star createProxy(BigStar bigStar){
        public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
        Star star = (Star) Proxy.newProxyInstance(
                ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if("cleanWC".equals(method.getName())){
                            System.out.println("攔截,不調(diào)用大明星的方法");
                            return null;
                        }
                        //如果是其他方法,正常執(zhí)行
                        return method.invoke(bigStar,args);
                    }
                }
        );
        return star;
    }
}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 解決mybatis一對(duì)多查詢(xún)r(jià)esultMap只返回了一條記錄問(wèn)題

    解決mybatis一對(duì)多查詢(xún)r(jià)esultMap只返回了一條記錄問(wèn)題

    小編接到領(lǐng)導(dǎo)一個(gè)任務(wù)需求,需要用到使用resultMap相關(guān)知識(shí),在這小編記錄下這個(gè)問(wèn)題的解決方法,對(duì)mybatis一對(duì)多查詢(xún)r(jià)esultMap項(xiàng)目知識(shí)感興趣的朋友一起看看吧
    2021-11-11
  • 淺析JDBC與數(shù)據(jù)庫(kù)如何進(jìn)行數(shù)據(jù)交互及類(lèi)型轉(zhuǎn)換

    淺析JDBC與數(shù)據(jù)庫(kù)如何進(jìn)行數(shù)據(jù)交互及類(lèi)型轉(zhuǎn)換

    本文主要介紹了JDBC在Java應(yīng)用程序與數(shù)據(jù)庫(kù)交互中的關(guān)鍵作用,詳細(xì)解釋了數(shù)據(jù)交互流程和數(shù)據(jù)類(lèi)型轉(zhuǎn)換機(jī)制,并提供了高級(jí)數(shù)據(jù)交互機(jī)制、優(yōu)化建議及實(shí)際驅(qū)動(dòng)示例,希望對(duì)大家有所幫助
    2026-04-04
  • Spring中ResponseBodyAdvice的使用詳解

    Spring中ResponseBodyAdvice的使用詳解

    這篇文章主要介紹了Spring中ResponseBodyAdvice的使用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • 2022?最新?IntelliJ?IDEA?詳細(xì)配置步驟演示(推薦)

    2022?最新?IntelliJ?IDEA?詳細(xì)配置步驟演示(推薦)

    作為一名開(kāi)發(fā)人員,第一肯定是選擇一款趁手的開(kāi)發(fā)利器,本人使用?Java?偏多,這里推薦使用?IntelliJ?IDEA,?俗稱(chēng)神級(jí)開(kāi)發(fā)工具,具體的安裝過(guò)程就不過(guò)多贅述了,有需要了解的朋友可以參考下本文
    2022-09-09
  • Springmvc完成ajax功能實(shí)例詳解

    Springmvc完成ajax功能實(shí)例詳解

    在本篇文章里小編給大家整理了關(guān)于Springmvc完成ajax功能實(shí)例內(nèi)容,有需要的朋友們可以參考學(xué)習(xí)下。
    2019-09-09
  • Spring Boot 整合 Druid過(guò)程解析

    Spring Boot 整合 Druid過(guò)程解析

    這篇文章主要介紹了Spring Boot 整合 Druid過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • 深入解析面向?qū)ο缶幊淘贘ava中的應(yīng)用小結(jié)

    深入解析面向?qū)ο缶幊淘贘ava中的應(yīng)用小結(jié)

    本文詳細(xì)介紹了面向?qū)ο缶幊痰幕靖拍?包括類(lèi)和對(duì)象、封裝、繼承和多態(tài),通過(guò)具體的Java代碼示例,展示了如何在Java中應(yīng)用這些面向?qū)ο缶幊痰暮诵乃枷?感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • 在寶塔面板中安裝OpenJDK-17的3種方法步驟

    在寶塔面板中安裝OpenJDK-17的3種方法步驟

    OpenJDK 17是Java Development Kit (JDK)的一個(gè)開(kāi)源實(shí)現(xiàn),由OpenJDK社區(qū)維護(hù),JDK是用于開(kāi)發(fā)和運(yùn)行Java應(yīng)用程序的核心工具包,這篇文章主要介紹了在寶塔面板中安裝OpenJDK-17的3種方法步驟,需要的朋友可以參考下
    2025-07-07
  • 學(xué)習(xí)Java設(shè)計(jì)模式之觀察者模式

    學(xué)習(xí)Java設(shè)計(jì)模式之觀察者模式

    這篇文章主要為大家介紹了Java設(shè)計(jì)模式中的觀察者模式,對(duì)Java設(shè)計(jì)模式感興趣的小伙伴們可以參考一下
    2016-01-01
  • Java線(xiàn)程中的用戶(hù)態(tài)和內(nèi)核態(tài)解讀

    Java線(xiàn)程中的用戶(hù)態(tài)和內(nèi)核態(tài)解讀

    這篇文章主要介紹了Java線(xiàn)程中的用戶(hù)態(tài)和內(nèi)核態(tài)解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06

最新評(píng)論

报价| 红安县| 永清县| 新建县| 福建省| 磐安县| 溆浦县| 当雄县| 万全县| 沂源县| 西林县| 周至县| 平泉县| 通渭县| 焉耆| 耿马| 大厂| 神池县| 海宁市| 中方县| 慈溪市| 西吉县| 永安市| 策勒县| 景德镇市| 津市市| 大厂| 绥棱县| 保德县| 河东区| 郸城县| 屏边| 黎城县| 监利县| 南康市| 洞口县| 麦盖提县| 南靖县| 公安县| 金堂县| 北碚区|