首页 > 其他分享 >反射和动态代理

反射和动态代理

时间:2023-09-01 21:33:38浏览次数:35  
标签:反射 name class 代理 final import 动态 public String

反射允许对成员变量,成员方法和构造方法的信息进行编程访问。

1、获取Class对象(字节码文件对象)的三种方式

①、Class.forName(“全类名”) (在源代码阶段使用)

②、类名.class (在加载阶段中使用)

③、对象.getClass() (在运行阶段使用)

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        //最为常用
        final Class<?> aClass = Class.forName("Test05.Student");
        System.out.println(aClass);
		
        //一般更多的时当做参数进行传递
        final Class<Student> studentClass = Student.class;
        System.out.println(studentClass);
		
        //需要有对象才可以使用
        Student s = new Student();
        final Class<? extends Student> aClass1 = s.getClass();

        System.out.println(aClass1 == aClass);			//true
        System.out.println(aClass == studentClass);		true

    }
}

2、反射获取构造方法

image.png

如果要获取指定的构造方法,可以给方法中添加和构造相同的参数,如下所示:

import java.lang.reflect.Constructor;

public class Test1 {
    public static void main(String[] args) throws NoSuchMethodException {
        //获取Student的字节对象
        final Class<Student> studentClass = Student.class;
        //获取指定参数的构造方法
        final Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(String.class);
        //int类型的形参
        studentClass.getDeclaredConstructor(int.class);
        System.out.println(declaredConstructor);

    }
}

3、利用反射获取成员方法

image.png

4、利用反射获取成员方法

image.png

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test1 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //创建调用方法的对象
        Student stu = new Student();
        //获取字节码对象
        final Class<Student> clazz = Student.class;
        //获取方法:第一个参数为方法名,第二个参数为方法中的形参
        final Method method1 = clazz.getDeclaredMethod("show", String.class);

        //参数一:表示调用方法的对象
        //参数二:表示给调用方法中传递的形参
        method1.invoke(stu,"是酋长呀!");

    }
}
5、反射的作用

①、获取一个类里面所有的信息,获取到了之后,再执行其它的业务逻辑。

②、结合配置文件,动态的创建对象并调用方法。

5.1、案例一:对于任意一个对象,都可以把对象所有的字段名和值保存到文件中。

image.png

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;

public class Test1 {
    public static void main(String[] args) {
        Student stu = new Student("张三", 121);
        try {
            saveObject(stu);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    //封装成一个方法
    public static void saveObject(Object obj) throws IOException, IllegalAccessException {
        //获取字节码对象
        final Class<?> clazz = obj.getClass();
        //创建io流
        BufferedWriter bw = new BufferedWriter(new FileWriter("F:\\Java基础\\Test02\\bb\\Information.txt"));
        //获取所有的成员变量
        final Field[] fields = clazz.getDeclaredFields();
        //遍历上面的成员变量
        for (Field field : fields) {
            //先暂时取消访问权限
            field.setAccessible(true);
            //获取成员变量的名称
            final String name = field.getName();
            //获取成员变量的值,参数为一个对象
            final Object value = field.get(obj);
            //写出数据
            bw.write(name + " = " + value);
            //换行
            bw.newLine();
        }
        //关闭io流的资源
        bw.close();
    }
}

5.2、案例二:反射可以跟配置文件(后缀为properties的文件)结合的方式,动态的创建对象,并调用方法。

配置文件:

image.png

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Test1 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //读取配置文件的信息
        Properties prop = new Properties();
        //创建io流
        FileInputStream fis = new FileInputStream("F:\\Java基础\\Test02\\prop.properties");
        //加载
        prop.load(fis);
        //关闭资源
        fis.close();

        //获取全类名和方法
        final String className = (String) prop.get("classname");
        final String methodName = (String) prop.get("method");

        //利用反射创建对象并且运行方法
        final Class<?> clazz = Class.forName(className);
        //获取构造方法
        final Constructor<?> con = clazz.getDeclaredConstructor();
        //通过构造方法创建对象
        final Object o = con.newInstance();

        //获取成员方法并运行
        final Method method = clazz.getDeclaredMethod(methodName);
        //设置临时访问权限
        method.setAccessible(true);
        //调用方法,对象为上面通过构造方法创建的那个
        method.invoke(o);

    }
}

6、动态代理

image.png

步骤一:创建类

public class BigStar implements Star {
    private String name;
    private int age;

    //实现唱歌的方法
    @Override
    public void sing(String name) {
        System.out.println(this.name + "正在唱" + name);
    }

    //实现跳舞的方法
    @Override
    public void dance() {
        System.out.println(this.name + "正在跳舞");
    }


    public BigStar() {
    }

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

    /**
     * 获取
     *
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     *
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     *
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "BigStar{name = " + name + ", age = " + age + "}";
    }
}

步骤二:把类中需要代理的方法添加封装成一个接口,所以类中需要实现接口中的抽象方法。

/**
 * 定义接口
 * */
public interface Star {
    //唱歌的抽象方法
    void sing(String name);
    //跳舞的抽象方法
    void dance();
}

步骤三:封装生成代理的类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyUtil {
    //私有化构造方法
    private ProxyUtil() {

    }

    //产生代理
    public static Star creatProxy(BigStar bigStar) {
        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 ("sing".equals(method.getName())) {
                            System.out.println("准备话筒,布置舞台!");
                        } else if ("dance".equals(method.getName())) {
                            System.out.println("准备舞伴,布置舞台!");
                        }
                        //利用反射调用BigStar中的方法
                        return method.invoke(bigStar, args);
                    }
                }
        );
        return star;
    }


}

步骤四:通过生成代理的类生成一个代理对象,然后通过这个对象调用相应的方法

public class Test {
    public static void main(String[] args) {
        //创建对象
        BigStar bigStar = new BigStar("邓紫棋", 28);
        //获取代理的对象
        final Star star = ProxyUtil.creatProxy(bigStar);

        //通过代理调用里面的方法
        star.sing("倒数");
        star.dance();

    }
}

最后输出结果:

准备话筒,布置舞台! 邓紫棋正在唱倒数 准备舞伴,布置舞台! 邓紫棋正在跳舞

标签:反射,name,class,代理,final,import,动态,public,String
From: https://blog.51cto.com/u_15433911/7326391

相关文章

  • 25. 反射
    一、什么是反射  反射,本质上就是通过字符的形式去操作对象/模块中的成员。在Python中,我们可以通过三个内置函数去实现反射相关的功能。getattr(object,name)#获取对象中的成员setattr(object,name,value)#设置对象中的成员hasattr(object,......
  • Vue进阶(幺伍玖):动态样式设置
    (文章目录)一、需求在Vue项目开发过程中,需要根据按钮数量动态设置icon元素宽度。二、分析在el-col标签内,若只展示1个icon元素的话,则设置宽度为100%;若显示2个icon元素的话,则设置宽度为50%;以此类推...三、解决方法<el-colv-for="(btn,index)inbtnArr":key="index":sty......
  • 虚拟机有代理备份、无代理备份是什么?
    有代理备份:在虚拟机内部安装备份代理程序,然后把虚拟机当作物理机一样来进行备份任务。借助虚拟机系统中内置的程序来进行备份的,就像在正常系统中备份那样,借助备份和还原(Windows7)功能对系统进行备份。但是这种方法操作起来比较麻烦,而且也没有办法进行批量化操作,比如有大量的虚拟机,都......
  • AMEYA360代理 | 佰维eMMC、LPDDR存储芯片赋能电视终端流畅体验
    5G、AI、VR、AR等技术的发展,助推智能电视、机顶盒等电视终端成为智能家居领域不可忽视的重要设备。随着4K超高清(UHD)技术、虚拟现实技术(VR)和增强现实技术(AR)的普及,并向8K超高清技术,电视终端将可以为消费者提供更清晰的视觉体验和更身临其境的观赏、游戏体验。同时,电视终端将不......
  • [代码随想录]Day33-动态规划part01
    题目:509.斐波那契数思路:动规五部曲:这里我们要用一个一维dp数组来保存递归的结果确定dp数组以及下标的含义dp[i]的定义为:第i个数的斐波那契数值是dp[i]确定递推公式为什么这是一道非常简单的入门题目呢?因为题目已经把递推公式直接给我们了:状态转移方程dp[i]=dp[i-......
  • WPF 动态更改启动窗体startupUri
    第一步:在App.xaml里,把StartupUri=""去掉,改成Startup="Application_Startup"第二步:在App.xaml.cs里,增加Application_Startup事件:privatevoidApplication_Startup(objectsender,StartupEventArgse){ApplicationcurrApp=Application.Current;currAp......
  • (!重要)25动态数据传递/布局综合案例
        获取自身的脚本,持有脚本调用自身的方法更新自己   ......
  • 如何进行C++动态转换
       ......
  • Java的反射机制
    JAVA反射机制:程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection(反射机制)。概述:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对......
  • 动态规划-区间DP
    动态规划-区间DP1.区间DP的概念区间DP,顾名思义就是在一个个的区间上进行DP。2.区间DP问题-石子合并https://www.acwing.com/problem/content/284/我们还是从动态规划的两个角度来阐述该问题。1.状态表示本问题,我们可以用二维状......