java反射与动态代理的理解

一、什么是反射机制?

  反射的官方定义是这样的:在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息及动态调用类对象方法的功能称为java的反射机制。  

  讲的通俗一点的话就是,对于jvm来说,.java文件必须要先编译为.class文件才能够被jvm执行,所以在编译为.class文件的过程中,对象的类型都会被指定好,比如说 User user。那么如果说我想在代码运行的过程中获取到对象的类型呢?或者说程序在运行过程中如何载入一个特定的类呢?这就涉及到了java的反射机制了,反射提供了一套能够让我们在代码运行时也能获取到类型属性的方法。

二、反射的使用

  jdk提供了三种方式获取一个对象的Class,就User user来说

  1.user.getClass(),这个是Object类里面的方法

  2.User.Class属性,任何的数据类型,基本数据类型或者抽象数据类型,都可以通过这种方式获取类

  3.Class.forName(""),Class类提供了这样一个方法,让我们通过类名来获取到对象类

  这三种方法用的最多的就是第三种,那么获取到类之后,Class类提供了很多获取类属性,方法,构造方法的api。

  1.获取所有的属性

//获取整个类
            Class c = Class.forName("java.lang.Integer");
              //获取所有的属性?
            Field[] fs = c.getDeclaredFields();  

                   //定义可变长的字符串,用来存储属性
            StringBuffer sb = new StringBuffer();
            //通过追加的方法,将每个属性拼接到此字符串中
            //最外边的public定义
            sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");
            //里边的每一个属性
            for(Field field:fs){
                sb.append("\t");//空格
                sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
                sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字
                sb.append(field.getName()+";\n");//属性的名字+回车
            }  

            sb.append("}");  

            System.out.println(sb);  

  2.获取特定的属性

 //获取类
    Class c = Class.forName("User");
    //获取id属性
    Field idF = c.getDeclaredField("id");
    //实例化这个类赋给o
    Object o = c.newInstance();
    //打破封装
    idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
    //给o对象的id属性赋值"110"
    idF.set(o, "110"); //set
    //get
    System.out.println(idF.get(o)); 

  3.获取方法

getDeclaredMethods()    获取所有的方法

getReturnType()    获得方法的放回类型

getParameterTypes()    获得方法的传入参数类型

getDeclaredMethod("方法名",参数类型.class,……)    获得特定的方法

getDeclaredConstructors()    获取所有的构造方法

getDeclaredConstructor(参数类型.class,……)    获取特定的构造方法

getSuperclass()    获取某类的父类

getInterfaces()    获取某类实现的接口

三、反射的作用和动态代理 

  反射作用总结就是:1.动态地创建类的实例,将类绑定到现有的对象中,或从现有的对象中获取类型。2.应用程序需要在运行时从某个特定的程序集中载入一个特定的类。

那么什么是动态代理呢?先给出百度的答案:动态代理,就是根据对象在内存中加载的Class类创建运行时类对象,从而调用代理类方法和属性。

  代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。而代理模式又分为静态代理和动态代理,先说静态代理。

  静态代理通俗点将就是自己手写一个代理类,而动态代理则不用我们手写,而是依赖于java反射机制,下面以一个demo举例。

  demo结构如图:

  

  Subject是一个普通接口,里面有个抽象的doSomething()的方法,而SubjectImpl.java是它的普通的实现类,如下所示。

    

  

  而HandProxy.java就是SubjectImpl的静态代理类,代替了SubjectImpl完成doSomething的工作,如下所示

  

  这样做的好处是对于doSomething方法来说,我用静态代理类来实现,可以任意的在其中插入我需要额外做的事情,比如说记录日志。

  那么AutoProxy.java就是动态代理类了,具体如下所示。

  

  这里面首先想要做到动态代理,必须先实现这个InvocationHandler接口,然后我们主要看bind方法,参数tar是一个Object类型的对象,也就是需要被代理的对象SubjectImpl,

方法里面有一个Proxy类,这个Proxy类提供了很多方法,这里我们用的是newProxyInstance方法,它有三个参数,第一个是被代理类的类构造器,第二个指的是被代理类的接口,也就是Subject接口,第三个是实现这个代理的类,这里就是本类。具体的来说,这个方法执行了下面三步:

1.生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码,然后用参数里的classLoader加载这个代理类。

2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler的子类传入。

3.返回这个代理类实例,因为我们构造的代理类实现了interfaces(也就是我们程序中传入的subject.getClass().getInterfaces())里的所有接口,因此返回的代理类可以强转成Subject类型来调用接口中定义的方法。

  而在调用每个代理类每个方法的时候,都用反射去调h的invoke方法(也就是我们自定义的InvocationHandler的子类中重写的invoke方法),用参数传递了代理类实例、接口方法、调用参数列表,这样我们在重写的invoke方法中就可以实现对所有方法的统一包装了。

  总结一下,静态代理的优点是清晰易懂,但是如果说业务代码很多,那么在代理类里面必须全部重新调用一遍,很麻烦。而动态代理,利用java反射机制,动态的生成了一个代理类,直接调用代理方法即可。

四、总结

  反射这一块是博主最近在看框架源码的时候总是遇到这类问题所以刻意去整理了一下,里面有些东西其实我也研究的不是很深刻,动态代理这边的源码还有待深入挖掘,若有大神发现写的不对的地方,还请多多指教,谢谢。

原文地址:https://www.cnblogs.com/jacksontao/p/8552357.html

时间: 2024-08-07 05:41:35

java反射与动态代理的理解的相关文章

java反射与动态代理

Java反射与动态代理 Java反射机制可以动态地获取类的结构,动态地调用对象的方法,是java语言一个动态化的机制.java动态代理可以在不改变被调用对象源码的前提下,在被调用方法前后增加自己的操作,极大地降低了模块之间的耦合性.这些都是java的基础知识,要想成为一名合格的程序猿,必须掌握! Java反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为

Java反射以及动态代理(上)

在常用的各种框架中,反射与动态代理很常见,也很重要.本篇就对这一小节的内容基础性地总结. 首先需要了解什么是类型信息,以及RTTI与反射的关系与区别. Java中,使用Class对象来表示所有类的对象.利用Class对象来获取类中的成员变量,构造函数以及方法,这些内容我们称之为类型信息.RTTI的含义是,在运行时识别一个对象的类型,但有一个前提,就是类型在编译时必须已知,这样才能用RTTI识别,并利用这些信息做一些有用的事情.但是如果在编译时,程序没有办法获知到这个对象所属的类,怎样才能使用这个

java反射实现动态代理

参考:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html http://my.oschina.net/lyp3314/blog/136589 反射可以通过class来创建对象或者修改对象.这样就提供了一个操作对象的方法. 下面拷贝前辈的总结: <反射机制> 为了更好的理解java的反射机制,最好先对java的泛型有所了解.java泛型就是参数化类型,即为所操作的数据类型指定一个参数.如果只指定了<?>,

Java反射以及动态代理(下)-- 源码

承接上篇,本篇就主要介绍动态代理的实现机制. 首先说说怎么去实现一个动态代理.还是可以用一个接口,两种实现来概括,但是代理中的实现并不明显,后面详细看看源码. 接口: package com.changjiang.test.RFP01.testProxy; public interface DynamicInterface { public void testNoArgs(); public String testOneArgs(String name); } 原始实现类: package co

Java反射和动态代理

反射 通过反射的方式Class.forName("com.ahu.Person")可以获取class对象的实例以及其中的属性.方法.构造函数等 动态代理 动态代理:在不修改原业务的基础上,基于原业务方法,进行重新的扩展,实现新的业务. 例子: 1. 旧业务 买家调用action,购买衣服,衣服在数据库的标价为50元,购买流程就是简单的调用. 2. 新业务 在原先的价格上可以使用优惠券,但是这个功能在以前没有实现过,我们通过代理类,代理了原先的接口方法,在这个方法的基础上,修改了返回值.

Java反射机制动态代理

package com.kaige123;/** * 程序员 * @author 凯哥 */public interface Chengxuyuan {    /**     * 写代码方法     */    public void xiedaima(); } package com.kaige123;/** * 程序员接口实现类 * @author 凯哥 */public class ChengxuyuanImpl implements Chengxuyuan {    public voi

黑马程序员————java中类的加载、反射、动态代理、枚举

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 类的加载.反射.动态代理.枚举 一.类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. 1.加载: 就是指将class文件读入内存,并为之创建一个Class对象 ★★

Java开发人员必懂的基础——反射与动态代理

Java的反射与动态代理是java体系结构中较为底层的知识,初学者可能觉得没有太大的用处,但他们确实著名Spring框架IOC和AOP所用的最重要的内容.当我们需要开发更基础,更广泛的的代码时,就会用到这学知识了. 在此之前,我们先来了解一下java的类加载机制 JVM与类加载机制: /* * 1.JVM:当调用java命令来运行某个java程序时,该命令会启动一个java虚拟机进程,同一个JVM中的所有线程,所有变量都处于同一个进程里,都使用该JVM的内存区 * 2.JVM:运行下面两个测试类

十分钟理解Java中的动态代理

十分钟帮助大家理解Java中的动态代理,什么是动态代理?感兴趣的小伙伴们可以参考一下 若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. 一.概述1. 什么是代理我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家"委托"代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道背后的厂家究竟是谁,也就是说,"委托