Java反射

1、概念

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.

2、获取Class对象

这里先构造一个测试类

package com.example.demo2;

public class People {

    public int age;

    public String name;

    private double acount;

    public People(){

    }

    public People(int age, String name, double acount) {
        this.age = age;
        this.name = name;
        this.acount = acount;
    }

    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;
    }

    private double getAcount() {
        return acount;
    }

    private void setAcount(double acount) {
        this.acount = acount;
    }

}

  • 通过Class类的forName方法,这是一个静态方法,可能抛出异常ClassNotFoundException的异常,同时需要注意的是,传入的参数是包名+类名。
Class clz = Class.forName("com.example.demo2.People");
  • 直接通过类名得到
Class plz = People.class;

还可以通过某一个具体的对象来构建Class对象,这样就可以达到修改该对象的属性或者调用方法。

        People xudong = new People();
        xudong.setName("张三");
        xudong.setAge(25);
        Class peopleclz = xudong.getClass();

3、获取构造方法

pulic类型的构造函数直接通过

plz.getConstructor()

私有类构造函数通过

plz.getDeclaredConstructor()

也可以获取构造方法的数组

// 获取全部构造函数
Constructor[] constructors=plz.getConstructors();
System.out.println("全部构造函数");
for(Constructor con:constructors){
    System.out.println(con.getName());
    Parameter[] parameters=con.getParameters();
    for(Parameter parameter:parameters){
        System.out.println("\t"+parameter.getName()+" 类型: "+parameter.getType());
    }
}

输出结果
在这里插入图片描述

4、获取全部成员和方法

        // 获取全部成员
        Field[] fields = plz.getDeclaredFields();
        System.out.println("全部成员");
        for(Field field:fields){
            System.out.println("\t"+field.getName());
        }
        // 获取全部函数
        Method[] methods = plz.getDeclaredMethods();
        System.out.println("全部函数");
        for (Method method:methods){
            System.out.println("\t"+method.getName());
        }

5、获取私有方法并调用

        // 获取私有方法
        Method setAccount = plz.getDeclaredMethod("setAcount", double.class);
        // 非常重要,破解private
        setAccount.setAccessible(true);
        setAccount.invoke(people,10000.0);

私有成员,私有方法都可以通过getDeclared***方法获得,如果下一步需要对其进行调用,就调用setAccessiable方法,让其变得可访问便可以对其调用了。

6、注意事项

  • 如果方法参数是double,int 之类的包装类型,那么也要通过double.class, int,class去获得该方法。
  • 对于private类型的成员或者方法,通过setAccessible(true);改变其访问性。
  • 通过反射调用方法时,注意参数的类型。

7、动态代理

通过动态代理,我们可以在不改动某个类的前提下,为其增加某些功能,比如增加日志记录的功能等,spring中就大量运用了动态代理,这里我们实现一个最简单的动态代理,需要用到InvocationHandler接口和Proxy类。

interface Subject{
    public void dosomething();

    public String sayHello();
}
// 需要被代理的类
class SubjectImpl implements Subject{
    public SubjectImpl() {
    }

    @Override
    public void dosomething() {
        System.out.println("I am doing something");
    }

    @Override
    public String sayHello() {
        return "Hello world!";
    }
}
// 代理类
public class SubjectProxy implements InvocationHandler {

    private Subject subject;

    public SubjectProxy(Subject sub){
        subject=sub;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理前,做一些比如日志记录等功能");
        // 实现方法的调用
        Object obj = method.invoke(subject,args);
        System.out.println("代理后");
        return obj;
    }

    public static void main(String[] args){
        Subject sub=new SubjectImpl();

        SubjectProxy subjectProxy=new SubjectProxy(sub);

        Subject subProxy = (Subject) Proxy.newProxyInstance(
                sub.getClass().getClassLoader(),
                sub.getClass().getInterfaces(),
                subjectProxy
        );

        subProxy.dosomething();
        System.out.println(subProxy.sayHello());

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值