当前位置: 代码网 > it编程>编程语言>Java > Java反射和动态代理的使用解读

Java反射和动态代理的使用解读

2025年02月08日 Java 我要评论
1、反射1.1 反射的概述是在运行状态中,不用创建对象就能够调用任意一个类的所有属性和方法;1.2 反射作用反射都是从class字节码文件中获取的内容。获取class字节码文件的对象利用反射如何获取构

1、反射

1.1 反射的概述

是在运行状态中,不用创建对象就能够调用任意一个类的所有属性和方法;

1.2 反射作用

反射都是从class字节码文件中获取的内容。

  • 获取class字节码文件的对象
  • 利用反射如何获取构造方法(创建对象)
  • 利用反射如何获取成员变量(赋值,获取值)
  • 利用反射如何获取成员方法(运行)

1.3 获取字节码文件对象的方式

  • class这个类里面的静态方法forname(“全类名”)(最常用)
  • 通过class属性获取,一般更多的是当做参数进行传递
  • 通过对象获取字节码文件对象,当我们已经有了这个类的对象时,才可以使用。
public class reflectdemo {
    public static void main(string[] args) throws classnotfoundexception {
        //1. 第一种方式
        //全类名 : 包名 + 类名
        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 字节码文件和字节码文件对象

  • java文件(源代码阶段):就是编写的java代码。
  • 字节码文件(加载阶段):就是通过java文件编译之后的class文件(是在硬盘上真实存在的,用眼睛能看到的)
  • 字节码文件对象(运行阶段):当class文件加载到内存之后,虚拟机自动创建出来的对象。这个对象里面至少包含了:构造方法,成员变量,成员方法。

反射获取的是字节码文件对象,这个对象在内存中是唯一的。

1.5 获取构造方法

规则:

  • get表示获取
  • declared表示私有
  • 最后的s表示所有,复数形式
  • 如果当前获取到的是私有的,必须要临时修改访问权限setaccessible(true),否则无法使用
public class reflectdemo {
    public static void main(string[] args) throws classnotfoundexception, nosuchmethodexception, invocationtargetexception, instantiationexception, illegalaccessexception {

        //1.获取class字节码文件对象
        class clazz = class.forname("com.ya.reflect.demo02.student");

        //2.获取构造方法
        // 2.1 返回所有公共构造方法对象的数组
        system.out.println("-----返回所有公共构造方法对象的数组----");
        constructor[] con1 = clazz.getconstructors();
        for (constructor con : con1) {
            system.out.println(con);
        }

        // 2.2 返回所有构造方法对象的数组
        system.out.println("-------返回所有构造方法对象的数组------");
        constructor[] con2 = clazz.getdeclaredconstructors();
        for (constructor con : con2) {
            system.out.println(con);

        }

        // 2.3 返回所有构造方法对象的数组
        system.out.println("-------返回单个公共构造方法对象------");
        constructor con3 = clazz.getconstructor(string.class);
        system.out.println(con3);
        //2.4 获取指定的空参构造
        system.out.println("-------获取指定的空参构造------");
        constructor con4 = clazz.getconstructor();
        system.out.println(con4);


        // 2.5 返回所有构造方法对象的数组
        system.out.println("-------返回单个构造方法对象------");
        constructor con5 = clazz.getdeclaredconstructor(string.class,int.class);
        system.out.println(con5);


        system.out.println("-----获取构造方法的权限修饰符(返回整数)--------");
        // 返回的是整数,public 1,private 2,protected 4,abstract 1024
        int modifiers = con5.getmodifiers();
        system.out.println(modifiers);

        system.out.println("-----获取构造方法的参数--------");
        parameter[] parameters = con5.getparameters();
        for (parameter parameter : parameters) {
            system.out.println(parameter);
        }

        system.out.println("--------创建对象-----------");
        //暴力反射:表示临时取消权限校验
        con5.setaccessible(true);   // 如果这个权限修饰符是私有的,就要取消权限校验
        student stu = (student) con5.newinstance("张三", 23);
        system.out.println(stu);
    }
}

1.6 获取构造方法并创建对象

public class reflectdemo02 {
    public static void main(string[] args) throws classnotfoundexception, nosuchmethodexception, invocationtargetexception, instantiationexception, illegalaccessexception {
        
        //需求1:获取空参,并创建对象(所创建的对象的属性是默认值)
        //1.获取整体的字节码文件对象
        class clazz = class.forname("com.ya.reflect.demo02.student");
        //2.获取空参的构造方法
        constructor con = clazz.getconstructor();
        //3.利用空参构造方法创建对象
        student stu = (student) con.newinstance();
        system.out.println(stu);

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

        //需求2:获取带参构造,并创建对象
        //1.获取整体的字节码文件对象
        class clazz2 = class.forname("com.ya.reflect.demo02.student");
        //2.获取有参构造方法
        constructor con2 = clazz2.getdeclaredconstructor(string.class, int.class);
        //3.临时修改构造方法的访问权限(暴力反射)
        con2.setaccessible(true);
        //4.直接创建对象
        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字节码文件的对象
        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.获取单个的成员变量
        system.out.println("-----获取单个的成员变量----");
        field fieldname = clazz.getdeclaredfield("name");
        system.out.println(fieldname);
        system.out.println("-----获取成员变量的数据类型----");
        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("-----修改对象里面记录的值---");
        fieldname.set(student,"lisi");
        system.out.println(student);
    }
}

1.8 获取成员方法

public class reflectdemo {
    public static void main(string[] args) throws classnotfoundexception, nosuchmethodexception {
       
        //1. 获取class字节码文件对象
        class clazz = class.forname("com.ya.reflect.demo04.student");

        //2. 获取里面所有的方法对象(包含父类中所有的公共方法)
        system.out.println("-------获取里面所有的方法对象(包含父类中所有的公共方法)-----");
        method[] methods = clazz.getmethods();
        for (method method : methods) {
            system.out.println(method);
        }
        // 3. 获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)
        system.out.println("--获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)--");
        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.获取方法的修饰符(返回整数)
        system.out.println("-------获取方法的修饰符(返回整数)-----");
        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 获取成员方法并运行

public class reflectdemo {
    public static void main(string[] args) throws classnotfoundexception, nosuchmethodexception, invocationtargetexception, illegalaccessexception {
        //1. 获取class字节码文件对象
        class clazz = class.forname("com.ya.reflect.demo04.student");
        //2. 获取指定的单一方法
        method eatmethod = clazz.getdeclaredmethod("eat", string.class); 
        // 3. 方法运行
        system.out.println("-------方法运行-----");
        student student = new student();
        eatmethod.setaccessible(true);
        string result = (string) eatmethod.invoke(student, "汉堡包");
        system.out.println(result);
    }
}

2. 动态代理

2.1 动态代理好处

  • 无侵入式的给方法增强功能。
  • 调用者(bitstar)–>代理(proxyutil)–>对象(star)

2.2 动态代理三要素

  • 接口:代理对象,被代理类和代理类都需要实现这个接口(本例是star)
  • 代理类:通过proxy类动态生成的代理类(本例是proxyutil)
  • 被代理类:代理类实例,它会代替被代理对象处理方法调用(本例是bigstar)

注:代理可以增强或者拦截的方法都在接口中,接口需要写在newproxyinstance的第二个参数里。

2.3 动态代理简单实现

//代理对象
public interface star {
	//可以把所有想要被代理的方法定义在接口当中
    //唱歌
    public abstract string sing(string name);
    //跳舞
    public abstract void dance();
}
//被代理类
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 + "}";
    }
}


//代理类
// 创建代理   java.lang.reflect.proxy类:提供了为对象产生代理对象的方法
public static object newproxyinstance(classloader loader, class<?>[] interfaces, invocationhandler h)
参数一:用于指定用哪个类加载器,去加载生成的代理类
参数二:指定接口,这些接口用于指定生成的代理有哪些方法
参数三:用来指定生成的代理对象要干什么事情
   
public class proxyutil {

    /**
     *  形参:被代理的明星对象
     *  返回值:给明星创建的代理
     */
    public static star createproxy(bigstar bigstar){
        // 创建代理
        // 这个代码没有显示实现star接口,但通过 jdk动态代理机制 隐式地为生成的代理类添加了star接口的实现,从而可以看作实现了star接口
        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 {
                        /**
                         * 参数一:代理的对象,即star变量引用的对象
                         * 参数二:要运行的方法,sing,dance
                         * 参数三:调用sing方法时,传递的实参
                         */
                        if("sing".equals(method.getname())){
                            system.out.println("准备话筒,收钱");
                        }else if("dance".equals(method.getname())){
                            system.out.println("准备场地,收钱");
                        }
                        //去找大明星开始唱歌或者跳舞
                        //代码的表现形式:调用大明星里面唱歌或者跳舞的方法
                        return method.invoke(bigstar,args);
                    }
                }
        );
        return star;
    }
}

//代理测试
public class test {
    public static void main(string[] args) {
        //1. 获取代理的对象
        bigstar bigstar = new bigstar("机哥");
        star proxy = proxyutil.createproxy(bigstar);

        //2. 调用唱歌的方法
        string result = proxy.sing("只因你太美");
        system.out.println(result);
    }
}

2.4 动态代理扩展

动态代理,还可以拦截方法。比如:在这个故事中,经纪人作为代理,如果别人让邀请大明星去唱歌,打篮球,经纪人就增强功能。但是如果别人让大明星去扫厕所,经纪人就要拦截,不会去调用大明星的方法。

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("拦截,不调用大明星的方法");
                            return null;
                        }
                        //如果是其他方法,正常执行
                        return method.invoke(bigstar,args);
                    }
                }
        );
        return star;
    }
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com