Java反射机制以及动态代理

Java反射机制

含义与功能

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods

Class类

认识Class类:

Class类是一个比较特殊的类,它是反射机制的基础 ,对于一个字节码文件.class,虽然表面上我们对该字节码文件一无所知,但该文件本身却记录了许多信息。Java在将.class字节码文件载入时,JVM将产生一个java.lang.Class对象代表该.class字节码文件,从该Class对象中可以获得类的许多基本信息,这就是反射机制。所以要想完成反射操作,就必须首先认识Class类。

在Java中程序获得Class对象有如下3种方式:

  • 使用Class类的静态方法forName(String className),其中参数className表示所需类的全名。例如:Class example = Class.forName("top.changtong1819.java.test")

    看着挺眼熟,这不就是学JDBC时连接数据库时的写法吗?Class.forName(xxxx)

  • 用类名调用该类的class属性来获得该类对应的Class对象,即“类名.class”。

    例如:Class example = test.class

  • 用对象调用getClass()方法来获得该类对应的Class对象,即“对象.getClass()”。

    例如:Class example = new Test("haha").getClass()

通过类的class属性获得该类所对应的Class对象,会使代码更安全,程序性能更好,因此大部分情况下建议使用第二种方式。使用功能”.class”来创建Class对象的引用时,不会自动初始化该Class对象,使用forName()会自动初始化该Class对象。

创建实例对象:

创建运行时类的对象,使用newInstance(),实际上就是调用运行时指定类的无参构造方法。

 public void test() throws Exception{
Class example =Class.forName("top.changtong1819.Person");
Person person = (Person)example.newInstance();
}

这里单单使用无参构造自然是不行的,满足不了实际使用需求,因此我们还需要想办法创建带参构造,这就是下面要讲的构造器的使用了。

类的反射

获取成员方法:一个成员方法就是一个Method对象

  • getMethods()返回该类继承以及自身声明的所有public的方法数组
  • getDeclaredMethods()返回该类自身声明的所有public的方法数组,不包括继承而来
//用invoke(Object, Object...)可以调用该方法
//带参的public方法:第一个参数是方法名,后面的可变参数列表是参数类型的Class类型
Method test = example.getMethod("test",String.class);
//调用获得的方法,调用时候传递参数
test.invoke(person,"hehe");

获取成员变量:一个成员变量就是一个Fields对象

  • getFields()获取所有的public的成员变量信息,包括继承的。
  • getDeclaredFields()获取该类自己声明的成员变量信息,public,private等

获取Java语言修饰符的int返回值:可调用Modifier.toString()获取修饰符的字符串形式:

  • getModifiers()以整数形式返回由此对象表示的字段的 Java 语言修饰符。

获取注释:

  • getAnnotations()返回此元素上存在的所有注释。
  • getDeclaredAnnotations()返回直接存在于此元素上的所有注释。

获取构造函数Constructor对象

  • getConstructors()返回所有public构造方法
  • getDeclaredConstructors() 返回类的所有构造方法
//Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数。
Person person = (Person) constructor.newInstance("p", "person");

动态代理

动态代理是指通过代理类来调用它对象的方法,并且是在程序运行使其根据需要创建目标类型的代理对象。它只提供一个代理类,我们只需要在运行时候动态传递给需要他代理的对象就可以完成对不同接口的服务了。

在Java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。

InvocationHandler接口:

每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。

Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy:  指代我们所代理的那个真实对象
method:  指代的是我们所要调用真实对象的某个方法的Method对象
args:  指代的是调用真实对象某个方法时接受的参数

Proxy类

Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法。

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

loader:  一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h:  一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

动态代理示例:

//定义一个接口
public interface Person{
void say();
void eat();
} //定义该接口的实现类
public class Man implements Person{
void say(){
System.out.println("多喝岩浆");
}
void eat(){
System.out.println("人在家中坐,狗粮天上来");
}
} //定义一个动态代理
public class SingleProxy implements InvocationHandler{
//先声明我们要代理的真实对象
private Object person;
//构造方法,给真实对象赋值
public SingleProxy(Object person){
this.person = person;
}
public Object invoke(Object person, Method method, Object[] args) throws Throwable{
//在代理真实对象前,我们可以添加操作进行增强
System.out.println("咱是单身狗");
//调用真实对象的方法
method.invoke(person,args);
//在代理对象之后,依旧可以增强操作
System.out.println("省钱又省心-->别问,问就是等相亲");
return null;
}
} //主类
public class programmer{
public static void main(String [] args){
//要代理的对象
Man man = new Man();
//将真实对象传入代理类中去
InvocationHandler handler = new SinglerProxy(man);
/*
* 通过Proxy类的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数man.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
Person person = (Person)Proxy.newProxyInstance(handler.getClass().getClassLoader(), man.getClass().getInterfaces(), handler);
person.eat();
person.say();
//这样,动态代理就算完成了
}
}

Java反射机制以及动态代理的更多相关文章

  1. java反射机制与动态代理

    在学习HadoopRPC时.用到了函数调用.函数调用都是採用的java的反射机制和动态代理来实现的,所以如今回想下java的反射和动态代理的相关知识. 一.反射 JAVA反射机制定义: JAVA反射机 ...

  2. Java反射机制可以动态修改实例中final修饰的成员变量吗?

    问题:Java反射机制可以动态修改实例中final修饰的成员变量吗? 回答是分两种情况的. 1. 当final修饰的成员变量在定义的时候就初始化了值,那么java反射机制就已经不能动态修改它的值了. ...

  3. 【java】java反射机制,动态获取对象的属性和对应的参数值,并属性按照字典序排序,Field.setAccessible()方法的说明【可用于微信支付 签名生成】

    方法1:通过get()方法获取属性值 package com.sxd.test.controller; public class FirstCa{ private Integer num; priva ...

  4. java.lang.Class<T> -- 反射机制及动态代理

    Interface : Person package java_.lang_.component.bean; public interface Person { String area = " ...

  5. 【Java基础】java中的反射机制与动态代理

    一.java中的反射机制 java反射的官方定义:在运行状态下,可以获取任意一个类的所有属性和方法,并且可通过某类任意一对象实例调用该类的所有方法.这种动态获取类的信息及动态调用类中方法的功能称为ja ...

  6. Java的反射机制和动态代理

    介绍Java注解的时候,多次提到了Java的反射API.与javax.lang.model不同的是,通过反射API可以获取程序在运行时刻的内部结构.反射API中提供的动态代理也是非常强大的功能,可以原 ...

  7. java反射机制与动态加载类

    什么是java反射机制? 1.当程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言.我们认为java并不是动态语言,但是它却有一个非常突出的动态相关机制,俗称:反射. IT行业里这么说,没有 ...

  8. Java中的反射机制和动态代理

    一.反射概述 反射机制指的是Java在运行时候有一种自观的能力,能够了解自身的情况为下一步做准备,其想表达的意思就是:在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法:对于任意一个对象 ...

  9. java反射中的动态代理机制(有实例)

    在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...

随机推荐

  1. 让JS代码Level提升的忍者秘籍(实用)

    本文章共2377字,预计阅读时间5-10分钟. 前言 没有前言. 你准备好成为同事眼中深藏不露.高深莫测.阳光帅气的前端开发了吗? 那就开始吧! 本文秉承宗旨:代码实用与逼格并存. 提升JS代码Lev ...

  2. kettle 执行 kjb 临时文件夹 /tmp permission denied 问题

    编写完的 kettle job (kjb文件) 放在服务器上执行的时候出现了奇怪的错误: # 执行 kjb ./kitchen.sh -file:/opt/code/ods/ods_inc.kjb # ...

  3. P1162_填涂颜色(JAVA语言)(速看!全洛谷最暴力解法!QAQ)

    思路:看了看数据n<=30,于是我们可以暴力求解(主要是BFS学的不咋地~2333).枚举每个0的位置,看上下左右四个方向上是否都有1.都有1的话说明被1包围,即在闭合圈的内部,开个数组标记一下 ...

  4. Python 详解修饰器 附带 js使用修饰器

    修饰器 功能 修饰器的主要功能是,在不改变已有代码的情况下,为某一个类,方法等扩展功能 首先看这样一段代码 def foo(): for i in range(10): print(i) foo() ...

  5. 连续函数离散化-以SOGI为例

    0. 引言 0.1 本文内容 基于SOGI函数,将s域传递函数转换为离散的z域函数,并以m语言形式进行实现,在simulink中封装为m-function并进行验证 0.2 学到什么 离散化方法 函数 ...

  6. [源码解析] 并行分布式任务队列 Celery 之 消费动态流程

    [源码解析] 并行分布式任务队列 Celery 之 消费动态流程 目录 [源码解析] 并行分布式任务队列 Celery 之 消费动态流程 0x00 摘要 0x01 来由 0x02 逻辑 in komb ...

  7. Class类文件结构--访问标志

    访问标志的位置:在常量池结束之后的两个字节(16位)表示访问标志access_flags. 访问标志的作用:用于标识类或者接口层次的访问信息:比如该Class是类还是接口,是否为public类型.是否 ...

  8. Dynamics CRM邮箱配置

    Dynamics CRM对邮箱有很好的支持,开通邮箱后方便用户通过邮件进行Dynamics CRM的业务处理,同时也可以作为一直消息流提醒的手段应用于审批.通知等场景,可以做一些更深入的功能拓展. 本 ...

  9. JAVA JNI 中解决在C/C++跨线程FindClass失败

    在JAVA与C/C++交互时使用JNI接口: 先是在JAVA调用的C++方法中直接测试FindClass,使用获取到的jclass操作没有任何问题: 但是在调用的C++方法中起线程后,在线程中Find ...

  10. 原创:纯CSS美化单复选框(checkbox、radio)

    最重要的一点,隐藏选择框本身.不多说了,上代码: <!doctype html> <html> <head> <meta charset="utf- ...