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

  在常用的各种框架中,反射与动态代理很常见,也很重要。本篇就对这一小节的内容基础性地总结。

  首先需要了解什么是类型信息,以及RTTI与反射的关系与区别。

  Java中,使用Class对象来表示所有类的对象。利用Class对象来获取类中的成员变量,构造函数以及方法,这些内容我们称之为类型信息。RTTI的含义是,在运行时识别一个对象的类型,但有一个前提,就是类型在编译时必须已知,这样才能用RTTI识别,并利用这些信息做一些有用的事情。但是如果在编译时,程序没有办法获知到这个对象所属的类,怎样才能使用这个类呢?答案是,我们可以在运行时,让JVM加载这个类的Class对象。由于没有经过编译期的检查,所以这里在使用之前,JVM也要简单地检查这个对象,看它属于哪个特定的类,而后加载这个类的Class对象。所以RTTI与反射的区别就在于,前者是在编译时打开和检查.class文件,运行时加载所需的类的Class对象,而后者则是在运行时打开和检查.class文件,并加载所需要类的Class对象。

  举个例子:

class Test{
    public static void main(String[] args){
        new Dev();
    }
}

在对它进行编译时,如果包下没有Dev这个类,那么编译会报错:

C:\Users\BruceChan\Desktop\test>javac Test.java
Test.java:3: 错误: 找不到符号
                new Dev();
                    ^
  符号:   类 Dev
  位置: 类 Test
1 个错误

但如果我们修改为反射的方式:

class Test{
    public static void main(String[] args){
        try{
            Class.forName("Dev");
        }catch(ClassNotFoundException e){
            System.out.print(e.toString());
        }
    }
}

对其进行编译时会发现,即便在没有Dev这个类存在的情况下,编译还是会顺利进行,因为它是在运行时,用到这个Dev类时,才会加载这个类。

---------------------------------------------------------------------------------->

  接下来,这里用代码的形式小节一下反射技术中,常用的套路。反射中,有三种方法可以获得类型的Class对象:

try {
    Class cls1 = Class.forName("com.changjiang.test.RFP01.testReflect.MyClass");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
MyClass myClass = new MyClass();
Class cls2 = myClass.getClass();

Class cls3 = MyClass.class;

通过该类的Class对象,可以获得它的属性,方法,构造函数,这里只说一下它的方法调用,首先给出原始类:

package com.changjiang.test.RFP01.testReflect;

import java.util.Date;

public class MyClass {
    private int myInt;
    private String myString;

    public MyClass(){

    }

    public MyClass(int a){
        this.myInt = a;
        System.out.println(a);
    }

    public void Method2Void(){

    }

    public int Method2Int(){
        System.out.println("Method2Int has run");
        return 0;
    }

    public String Method2String(){
        return "";
    }

    public Object Method2Object() {
        return new Date();
    }

    public void Method3Param(int a, String b){
        System.out.println("Method3Param has run with param-a:" + a + " and param-b:" + b);
    }
}

再给出几个方法的调用以及输出:

package com.changjiang.test.RFP01;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import com.changjiang.test.RFP01.testReflect.MyClass;

public class Main {
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        Class cls = myClass.getClass();
        try{
             Method m = cls.getMethod("Method2Int", new Class[]{});//获取一个类的方法
             m.invoke(myClass, new Object[]{});//精髓所在,调用这个类的方法  

             Method m2 = cls.getMethod("Method3Param", new Class[]{int.class, String.class});
             m2.invoke(myClass, new Object[]{5, "fake"});//调用这个类的方法,带参数的  

             Constructor<MyClass> cons = cls.getConstructor(new Class[]{int.class});
             cons.newInstance(47);
         }catch(Exception e){
             e.printStackTrace();
         }
         Method[] ms = cls.getMethods();
         for(Method m:ms){
             System.out.print(m.getName()+"\t");
         }
    }
}

output:

Method2Int has run
Method3Param has run with param-a:5 and param-b:fake
47
Method2Int Method3Param Method2String Method2Object Method2Void wait wait wait equals toString hashCode getClass notify notifyAll

---------------------------------------------------------------------------------->

  OK,说到这里,我们该了解一下代理模式。清楚之后,我们再看动态代理。代理模式,简单地说,就是一个接口,两个实现。实现一中我们需要做一些事情,在实现二中,我们不仅要做实现一中的事情,而且可以在此之前与之后都添加我们想要做的别的事情。具体内容看看代码。

package com.changjiang.test.RFP01.testReflect;

public class SampleProxy {
    public static void main(String[] args) {
        new BaseSample1().doSomething();
        System.out.println("--------------------------------");
        new ProxySample(new BaseSample1()).doSomething();;
    }
}

interface BaseInterface{
    public void doSomething();
}

class BaseSample1 implements BaseInterface{
    public void doSomething() {
        System.out.println("BaseSample1");
    }
}

class ProxySample implements BaseInterface{
    private BaseInterface bi;
    public ProxySample(BaseInterface bi) {
        this.bi = bi;
    }
    public void doSomething() {
        System.out.println("before");
        bi.doSomething();
        System.out.println("after");
    }
}

这里的接口,被两个类实现,一个是原生类,另一个是代理类,而代理类中不但实现了这个接口,还需要将代理类通过构造器赋给自己的属性中,而后在接口实现方法中使用原始类的方法。

---------------------------------------------------------------------------------->

接下来看看动态代理,主要是如何实现动态代理以及核心类Proxy与其方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InovationHandler h)中几个参数的详细含义与作用剖析。(下篇)

时间: 2024-12-08 07:53:04

Java反射以及动态代理(上)的相关文章

java反射与动态代理

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

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反射与动态代理的理解

一.什么是反射机制? 反射的官方定义是这样的:在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息及动态调用类对象方法的功能称为java的反射机制. 讲的通俗一点的话就是,对于jvm来说,.java文件必须要先编译为.class文件才能够被jvm执行,所以在编译为.class文件的过程中,对象的类型都会被指定好,比如说 User user.那么如果说我想在代码运行的过程中获取到对象的类型呢?或者说程序在运行过程

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设计模式之动态代理 代理是基本的设计模式之一,它是你为了提供额外的或不同的操作,而插入的用来代替"实际"对象的对象.这些操作通常涉及与"实际"对象的通信,因此代理通常充当着中间人的角色,下面是一个用来展示动态代理结构的简单示例: /** 普通(非动态)代理示例: */ interface Interface { void doSomething(); void somethingElse(String arg); } class RealObject