zoukankan      html  css  js  c++  java
  • java反射机制详解

    一、什么是反射

    JAVA反射机制是在运行状态中,对于任何一个类,都能够知道这个类的所有属性和方法;对于任何一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

    想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。

    获取字节码文件对象(获取class对象的方式)的三种方式:

    1、根据类名:类名.class

    2、根据对象:对象.getClass()

    3、根据全限定类名:Class.forName(全限定类名)

    二、通过反射机制获取信息

    1、构造函数

    //获取字节码文件
    Class classs = Class.forName("com.zcbq.reflect.User");
    //先获取有参构造,parameterTypes:表述参数列表,也可以不写
    Constructor constructor = classs.getConstructor(int.class,String.class,int.class,String.class);
    //通过构造器来实例化对象,将实际的参数传进去
    User user = (User) constructor.newInstance(01,"小轩",13,"打球");

    获取全部构造函数:

    //获取字节码文件
    Class classs = Class.forName("com.zcbq.reflect.User");
    //获取所有构造函数
    Constructor constructor[] = classs.getConstructors();
    //遍历所有构造函数
    for(int i=0;i<constructor.length;i++){
        //获取每个构造函数中的参数类型字节码对象
        Class[] parameterTypes = constructor[i].getParameterTypes();
        System.out.println("第"+i+"个构造函数:");
        for (int j = 0; j < parameterTypes.length; j++) {
            System.out.println(parameterTypes[j].getName()+",");
        }
    }

    console:

    2、属性

    在学习spring ioc之时,对未提供set方法的private属性依然可以注入感到神奇万分,现在看来,这神奇的根源自然是来自于java的反射,常用的方法如下:

    2.1获取指定成员变量

    //获取字节码文件
    Class classs = Class.forName("com.zcbq.reflect.User");
    //获取其实例对象
    User user = (User) classs.newInstance();
    //获取成员变量classs.getField(name);通过name来获取指定成员变量
    //如果该成员变量是私有的,则应该使用getDeclaredField(name);
    Field declaredField = classs.getDeclaredField("userName");
    //因为属性是私有的,获得其对象后,还要让打开可见权限
    declaredField.setAccessible(true);
    //对成员变量进行操作
    //赋值操作
    declaredField.set(user, "Richard");
    System.out.println(user.getUserName());

    2.2获取全部属性

    //获取字节码文件
    Class classs = Class.forName("com.zcbq.reflect.User");
    //获取其实例对象
    User user = (User) classs.newInstance();
    //赋值操作
    user.setUserNum(01);
    user.setUserName("小轩");
    //将私有属性一并获得
    Field[] fields = classs.getDeclaredFields();
    //遍历所有属性
    for (int i = 0; i < fields.length; i++) {
    //打开可见权限
    fields[i].setAccessible(true);
    System.out.println(fields[i].get(user));
    }

    3、方法

    3.1不带参数的方法

    //获取字节码文件
    Class classs = Class.forName("com.zcbq.reflect.User");
    //获取其实例对象
    User user = (User) classs.newInstance();
    //不带参数的方法,name为不带参数的方法
    /*
    * classs.getMethod(name,paraMeterTypes)
    * name:方法的名称
    * paraMeterTypes:方法的参数类型,没有则什么都不填 例如:String.class 
    */
    Method method = classs.getMethod("name");
    //调用方法
    /*
    * method.invoke(obj,args)
    * obj:方法的对象
    * args:实际的参数值,没有则不填
    */
    method.invoke(user);

    3.2带参数的方法

    //获取字节码文件
    Class classs = Class.forName("com.zcbq.reflect.User");
    //获取其实例对象
    // User user = (User) classs.newInstance();
    //获取带参数的方法,为方法名
    // Method method = classs.getDeclaredMethod("namess", String.class);
    //设置可见性
    // method.setAccessible(true);
    //调用方法
    // method.invoke(user, "text");

    3.3获取所有的方法

    //获取字节码文件
    Class classs = Class.forName("com.zcbq.reflect.User");
    //获取其实例对象
    User user = (User) classs.newInstance();
    //获取所有的方法
    Method[] methods = classs.getMethods();
    //遍历所有方法
    for (Method method : methods) {
        //设置可见性
        method.setAccessible(true);
        System.out.println(method.getName());
        //获得方法的参数
        Class<?>[] parameterTypes = method.getParameterTypes();
        for (int i = 0; i < parameterTypes.length; i++) {
            //获得构造函数中参数类型
            System.out.println(parameterTypes[i].getName()+",");
        }
    }

    三、动态代理的概述及实现

    1、动态代理概述

    动态代理:利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对象);

    代理的是接口(Interfaces),不是类(Class),更不是抽象类。

    2、动态代理的实现

    分三步,但是注意JDK提供的代理正能针对接口做代理,也就是下面的第二步返回的必须要是一个接口。

    2.1 new出代理对象,通过实现InvacationHandler接口,然后new出代理对象来。

    2.2 通过Proxy类中的静态方法newProxyInstance,来将代理对象假装成那个被代理的对象,也就是如果叫人帮我们代买火车票一样,那个代理就假装成我们自己本人。

    2.3 执行方法,代理成功

    附属代码:

    package com.zcbq.proxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class MyInvocationHander implements InvocationHandler {
        private Object target;
    
        public MyInvocationHander() {
            super();
        }
    
        public MyInvocationHander(Object target) {
            super();
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // TODO Auto-generated method stub
            System.err.println("开始");
            method.invoke(target, args); //执行被代理的target对象的方法
            System.out.println("结束");
           return null;
        }
    
    }

    附属代码:

    Student student = new StuImp();
    MyInvocationHander m = new MyInvocationHander(student);
    /**
    * student.getClass().getClassLoader():类加载器
    * student.getClass().getInterfaces():被代理对象的接口
    * m:代理对象
    */
    Student s = (Student) Proxy.newProxyInstance(student.getClass().getClassLoader(), 
    student.getClass().getInterfaces(), m);
    s.login();
    s.logout();

    注意newProxyInstance的三个参数,第一个,类加载器,第二个被代理对象的接口,第三个代理对象。

  • 相关阅读:
    我要把铁路修到威斯特摩兰
    1新建空白jasperreport模板
    oracle权限
    swagger配置
    lombok插件基本使用
    oracle与sqlserver的区别
    yaml语法学习
    第一个SpringBoot
    spring多环境切换
    JSR303数据校验
  • 原文地址:https://www.cnblogs.com/myRichard/p/11742194.html
Copyright © 2011-2022 走看看