亚洲欧美日韩熟女|做爱高潮视频网址|国产一区二区三级片|国产Av中文字幕www.性色av|亚洲婷婷永久免费|国产高清中文字幕|欧美变态网站久re视频精品|人妻AV鲁丝第一页|天堂AV一区二区在线观看|综合 91在线精品

Android Java反射與Proxy動(dòng)態(tài)代理詳解與使用基礎(chǔ)篇(一)

2023-04-12


一、介紹


什么是反射?

反射是java語(yǔ)言的一個(gè)特性,它允程序在運(yùn)行時(shí)(注意不是編譯的時(shí)候)來進(jìn)行自我檢查并且對(duì)內(nèi)部的成員進(jìn)行操作。


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


為什么要用反射?

Java Reflection API簡(jiǎn)介

Java Reflection功能非常強(qiáng)大,并且非常有用,比如:


  • 獲取任意類的名稱、package信息、所有屬性、方法、注解、類型、類加載器等
  • 獲取任意對(duì)象的屬性,并且能改變對(duì)象的屬性
  • 調(diào)用任意對(duì)象的方法
  • 判斷任意一個(gè)對(duì)象所屬的類
  • 實(shí)例化任意一個(gè)類的對(duì)象
  • 通過反射我們可以實(shí)現(xiàn)動(dòng)態(tài)裝配,降低代碼的耦合度,動(dòng)態(tài)代理等。

在JDK中,主要由以下類來實(shí)現(xiàn)Java反射機(jī)制,這些類(除了第一個(gè))都位于java.lang.reflect包中


Class類:代表一個(gè)類,位于java.lang包下。


Field類:代表類的成員變量(成員變量也稱為類的屬性)。


Method類:代表類的方法。


Constructor類:代表類的構(gòu)造方法。


Array類:提供了動(dòng)態(tài)創(chuàng)建數(shù)組,以及訪問數(shù)組的元素的靜態(tài)方法。



二、反射的使用


1、創(chuàng)建類對(duì)象


正常我們創(chuàng)建類對(duì)象都是通過new關(guān)鍵字來創(chuàng)建,但是我們還有其他兩種方式


通過 Class 對(duì)象的 newInstance() 方法

通過 Constructor 對(duì)象的 newInstance() 方法

基礎(chǔ)數(shù)據(jù):

package com.example.mylibrary.ref;

public class MyPerson {
    private String name = "default";
    public int age = 2;
    protected boolean sex;


    private MyPerson(String name) {
        this.name = name;
    }

    protected MyPerson(int age) {
        this.age = age;
    }

    public MyPerson() {

    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    private String getPrivateName() {
        return name;
    }

    protected int getProtectAge() {
        return age;
    }
}

1.1通過 Class 對(duì)象的 newInstance() 方法



Class cls=Class.forName("com.example.mylibrary.ref.MyPerson"); MyPerson person=(MyPerson) cls.newInstance();




1.2通過 Constructor 對(duì)象的 newInstance() 方法



Constructor constructor=cls.getConstructor(); MyPerson myPerson=(MyPerson) constructor.newInstance();




以上都是構(gòu)造器無(wú)默認(rèn)參數(shù),如果有的話1.1已無(wú)法滿足,且1.1的方法在java9的時(shí)候已過期,接下我們主講1.2通過Constructor 創(chuàng)作對(duì)象


有參構(gòu)造:



1、public Constructor getConstructor(Class... parameterTypes)




要指定構(gòu)造器的參數(shù)類型,必須一一對(duì)其


2、public T newInstance(Object... initargs)


在獲取對(duì)象時(shí),需要傳入默認(rèn)參數(shù)




Constructor constructor=cls.getConstructor(String.class,Integer.TYPE); MyPerson myPerson=(MyPerson) constructor.newInstance("你好",12);




1.3.獲得成員變量Field

獲取成員變量有四種:



1、Field[] fields = cls.getFields(); 2、Field field = cls.getField("age"); 3、Field[] dcfis = cls.getDeclaredFields(); 4、Field dfied = cls.getDeclaredField("name");




getFields:獲取所有public的屬性變量


getField:獲取指定為public的屬性變量對(duì)象


getDeclaredFields:獲取所有變量,包括public、protect、private


getDeclaredField:獲取任性一個(gè)屬性對(duì)象,包括public、protect、private


看如下debug日志:



Field對(duì)象API介紹:

Field是獲取變量,變量就有修改值和獲取變量對(duì)象。


1.修改參數(shù)

field.set(cls,value)


2.獲取變量

Object value=field.get(cls);


value:就是對(duì)象本身


3.獲取對(duì)象類型

field.getType()


注意:

1.通過getDeclared獲取的是全部,如果方法前面沒有Declared基本獲取的就是public


2.如果field設(shè)置value異常不生效,需要設(shè)置field.setAccessible(true)


1.4構(gòu)造器的獲取

構(gòu)造器獲取區(qū)分public和全部,通過如下方式獲取




Constructor[] construPublic= cls.getConstructors();//public Constructor[] consrAll=cls.getDeclaredConstructors();//all Log.log(construPublic.length+""); Log.log(consrAll.length+"");





1.5.類的方法Method

Method是class中的方法,方法的獲取如下


1.Method[] methods = cls.getMethods();

這種獲取到的方法是當(dāng)前類下可用的所有public方法,包括class自身的一些方法



getMethods=wait
getMethods=equals
getMethods=toString
getMethods=hashCode
getMethods=getClass
getMethods=notify
getMethods=notifyAll


2.Method[] methodDecs= cls.getDeclaredMethods();

這種獲取的是當(dāng)前類下的所有方法,不包括class自身提供的,只有用戶定義的所有類型


getDeclaredMethods=getName
getDeclaredMethods=setName
getDeclaredMethods=getAge
getDeclaredMethods=setAge
getDeclaredMethods=getProtectAge
getDeclaredMethods=getPrivateName


1.6. 如何調(diào)用Method

先準(zhǔn)備一個(gè)對(duì)象:MyPerson person=new MyPerson();


1.無(wú)參數(shù)調(diào)用



Method method_getAge = cls.getMethod("getAge"); method_getAge.setAccessible(true); Object o = method_getAge.invoke(new MyPerson());




2.有參調(diào)用

Method method_setAge = cls.getMethod("setAge", Integer.TYPE); method_setAge.setAccessible(true);


method_setAge.invoke(person,122);


通過Method設(shè)置或者獲取都一樣,方法的調(diào)用通過invoke(),必須傳入當(dāng)前對(duì)象,后面有多少個(gè)參數(shù)就一一對(duì)應(yīng),沒有就不傳。


這樣基本就完成了反射的作用


注意:

Method提供了getDefaultValue(),這個(gè)方法是獲取注解提供的默認(rèn)值,不是獲取目標(biāo)類的值。如果不是通過注解設(shè)置默認(rèn)值,返回的是null。


1.7.內(nèi)部類的獲取

我們上面都是介紹單獨(dú)類,有些人說如果我的類是類部類怎么獲???其實(shí)很簡(jiǎn)單




Class clsParent = Class.forName("com.example.mylibrary.ref.Parent"); Class clsChild = Class.forName(clsParent.getName() + "$Child");




path=父類+$+內(nèi)部類名稱

二、動(dòng)態(tài)代理Proxy


掌握了基本的反射使用,那我們繼續(xù)了解動(dòng)態(tài)代理。我們經(jīng)常聽到Hook,鉤子說法很懸乎,也很科幻,一些公司面試喜歡聞,你會(huì)Hook嘛?其實(shí)就這些。沒有那么懸乎,剩下的就是Hook涉及到的復(fù)雜場(chǎng)景,任何復(fù)雜的代碼都是從基礎(chǔ)做起。


動(dòng)態(tài)代理通過Proxy類完成


1、獲取一個(gè)代理對(duì)象:newProxyInstance



public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) { Objects.requireNonNull(h); Class caller = System.getSecurityManager() == null ? null : Reflection.getCallerClass(); Constructor cons = getProxyConstructor(caller, loader, interfaces); return newProxyInstance(caller, cons, h); }




參數(shù)介紹

1.1、loader:加載器


1.2、interfaces:接口類接口,代理是通過代理類的接口進(jìn)行攔截,而不是直接修改方法體


1.3、InvocationHandler:攔截器


攔截器介紹:



public Object invoke(Object proxy, Method method, Object[] objects)




1、proxy:代理對(duì)象


2、method:代理對(duì)象調(diào)用的方法


3、objects:參數(shù)


小試牛刀:


public static void main(String[] args) throws Exception {
        final PersonInterface person = new Child("sun");


        Object proxy = Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                String name = method.getName();

                Log.log("Object o, Method method, Object[] objects----------");
                if (method.getName().equals("setName")) {
                    String item=(String) objects[0];
                    objects[0]="modify="+item;
                }

                return method.invoke(person, objects);

            }
        });

        if (proxy instanceof PersonInterface) {
            PersonInterface testPerson = (PersonInterface) proxy;
            testPerson.setName("proxy");
        }



        PersonInterface testPerson = (PersonInterface) proxy;
        testPerson.setName("proxy");

        Log.log(testPerson.getName());
    }
package com.example.mylibrary.ref;

import com.example.mylibrary.Log;

public class Child implements PersonInterface {
    String name = "";

    public Child(String name) {
        this.name = name;
    }

    @Override
    public String getName() {

        return name;
    }

    @Override
    public void setName(String name) {

        this.name = name;
    }


    public void show() {
        Log.log("name=" + name);
    }
}
package com.example.mylibrary.ref;

public interface PersonInterface {
    public String getName();
    public void setName(String name);

}




DEBUG日志






這樣,我們就完成了Hook了。記住,動(dòng)態(tài)代理是攔截接口,而不是修改方法體


本文僅代表作者觀點(diǎn),版權(quán)歸原創(chuàng)者所有,如需轉(zhuǎn)載請(qǐng)?jiān)谖闹凶⒚鱽碓醇白髡呙帧?/p>

免責(zé)聲明:本文系轉(zhuǎn)載編輯文章,僅作分享之用。如分享內(nèi)容、圖片侵犯到您的版權(quán)或非授權(quán)發(fā)布,請(qǐng)及時(shí)與我們聯(lián)系進(jìn)行審核處理或刪除,您可以發(fā)送材料至郵箱:service@tojoy.com