一、java中的反射机制

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

获取一个类的Class对象是应用反射机制的前提,获取Class对象的方式有如下三种:

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

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

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

1. 通过反射机制操作某个类的属性

package net.xsoftlab.baike;
import java.lang.reflect.Field;
public class TestReflect {
private String proprety = null;
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
Object obj = clazz.newInstance();
// 可以直接对 private 的属性赋值
Field field = clazz.getDeclaredField("proprety");
field.setAccessible(true);
field.set(obj, "Java反射机制");
System.out.println(field.get(obj));
}
}

2. 通过反射机制调用某个类的方法

package net.xsoftlab.baike;
import java.lang.reflect.Method;
public class TestReflect {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
// 调用TestReflect类中的reflect1方法
Method method = clazz.getMethod("reflect1");
method.invoke(clazz.newInstance());
// Java 反射机制 - 调用某个类的方法1.
// 调用TestReflect的reflect2方法
method = clazz.getMethod("reflect2", int.class, String.class);
method.invoke(clazz.newInstance(), 20, "张三");
// Java 反射机制 - 调用某个类的方法2.
// age -> 20. name -> 张三
}
public void reflect1() {
System.out.println("Java 反射机制 - 调用某个类的方法1.");
}
public void reflect2(int age, String name) {
System.out.println("Java 反射机制 - 调用某个类的方法2.");
System.out.println("age -> " + age + ". name -> " + name);
}
}

二、动态代理

2.1 动态代理AOP

java代理模式的定义:用一个对象来控制对另一个对象的访问,称控制对象为代理对象,被控制对象为被代理对象或真实对象。通过调用代理对象的方法来间接访问被代理对象中的同名方法,要保证二者具有同名方法通常将这些同名方法抽象成接口,由二者共同实现。

动态代理和静态代理的区别:静态代理必须要为每个真实类定义一个代理类,而动态代理中无需定义代理类,由java反射包中的Proxy类动态的创建代理对象或代理类。

在java的动态代理机制中,有一个类和接口至关重要,Proxy类用于动态创建代理类或代理对象,调度处理器接口InvocationHandler。每个动态代理对象必须与实现了InvocationHandler接口的实例关联,代理对象每个方法的内部都调用了此关联实例的invoke 方法,而invoke 方法的内部又利用反射机制调用真是对象的方法,从而实现了由代理对象访问真实对象的目的。

下面是实现动态代理的经典案例:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; //定义真实类和代理类共同的接口
interface Subject {
public void rent(); public void hello(String str);
} //定义真实类(被代理类
class RealSubject implements Subject {
@Override
public void rent() {
System.out.println("I want to rent my house");
} @Override
public void hello(String str) {
System.out.println("hello: " + str);
}
} //定义继承了InvocationHandler接口的调度处理器
public class MyInvocationHandler implements InvocationHandler {
//要代理的真实对象
private Object realObj; // 构造方法给要代理的真实对象赋值
public MyInvocationHandler(Object realObj) {
this.realObj = realObj;
} /**
* 执行动态代理对象的所有方法都会被替换为执行如下的invoke方法
* 其中:
* autoProxy:动态代理对象
* method:代表正在执行的方法
* args:由动态代理对象调用方法时传入的实参
*/
@Override
public Object invoke(Object autoProxy, Method method, Object[] args) throws Throwable {
//在代理真实对象前我们可以添加一些自己的操作
System.out.println("before rent invoke");
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
System.out.println("Method:" + method);
method.invoke(realObj, args);
//在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after rent invoke");
return null;
} } class Client {
public static void main(String[] args) {
//要代理的真实对象
Subject realObj = new RealSubject();
//要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler MyHandler = new MyInvocationHandler(realObj);
/*通过Proxy类的newProxyInstance方法动态创建代理对象
*public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
* 它的三个参数
* 第一个参数 指定动态代理类的类加载器
* 第二个参数 指定动态代理类需实现的接口集合
* 第三个参数 指定与该动态代理对象所关联的调度处理器实例
*/
Subject autoProxy = (Subject) Proxy.newProxyInstance(MyHandler.getClass().getClassLoader(), realObj.getClass().getInterfaces(), MyHandler);
System.out.println(autoProxy.getClass().getName());
autoProxy.rent();
autoProxy.hello("world");
}
}

输出如下:

net.xsoftlab.baike.$Proxy0
before rent invoke
Method:public abstract void net.xsoftlab.baike.Subject.rent()
I want to rent my house
after rent invoke
before rent invoke
Method:public abstract void net.xsoftlab.baike.Subject.hello(java.lang.String)
hello: world
after rent invoke

总结:1.动态代理中无需定义代理类,代理对象是由Proxy类动态产生的。

           2.代理对象对方法的访问都将转换成调度处理器对其invoke 方法的访问。

           3.调度处理器的invoke 方法内部利用反射机制去调用真是对象的同名方法。

          4.像上面这种动态代理在Spring中被称为AOP(Aspect Orient Programming,面向切面编程),AOP代理可替代目标对象,AOP代理包含了目标对象的全部方法。

2.2 AOP的应用

上面介绍了动态代理,接下来说下它的应用。在开发中如果要复用同一功能模块,可以通过复制该功能模块的代码来实现,但在开发中一般不会这样做,通常将该功能模块封装成一个方法,在需要的地方直接调用就可以了。

通过将公共模块封装成方法来调用虽然提高了复用减少了代码的冗余,但却提高了这三个代码段与方法的耦合。最理想的效果是:代码块一,代码块二,代码块三既可以执行蓝色区域的代码部分,又无需以硬编码的方式来直接调用蓝色区域的方法。这时就可以通过动态代理来实现这个功能。

接下来使用Proxy和InvocationHandler来实现当程序调用info()或run()方法时,系统可以“自动”将method1()和method2()两个方法插入info()和run()方法中执行。
首先提供一个Dog接口,在该接口中提供两个方法:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; interface Dog {
//info()方法声明
void info(); //run()方法
void run();
} class GunDog implements Dog {
//实现info方法,仅仅打印一个字符串
@Override
public void info() {
System.out.println("我是一只猎狗");
} //实现run()方法,仅仅打印一个字符串
@Override
public void run() {
System.out.println("迅速奔跑");
}
} class DogUtil {
public static void method1() {
System.out.println("=====模拟第一个通用方法=====");
} public static void method2() {
System.out.println("=====模拟第二个通用方法=====");
}
} class MyInvocationHandler implements InvocationHandler {
private Object target; public void setTarget(Object target) {
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//执行DogUtil对象中method1方法
DogUtil.method1();
//以target作为主调执行method方法
Object result = method.invoke(target, args);
//执行DogUtil对象中的method2方法
DogUtil.method2();
return result;
}
} class MyProxyFactory {
public static Object getProxy(Object target) {
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
//设置需要代理的对象
myInvocationHandler.setTarget(target);
//创建并返回动态代理
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myInvocationHandler);//使用指定的类加载器,需要实现的接口,自定义Handler
}
} public class TestAOP {
public static void main(String[] args) {
Dog dog = (Dog) MyProxyFactory.getProxy(new GunDog());
dog.info();
dog.run();
}
}

输出如下:

=====模拟第一个通用方法=====
我是一只猎狗
=====模拟第二个通用方法=====
=====模拟第一个通用方法=====
迅速奔跑
=====模拟第二个通用方法=====

下面这张图片对上面的程序流程进行了简单解释:

本篇博文参考了:【java】解析java类加载与反射机制    java的动态代理机制详解

【Java基础】java中的反射机制与动态代理的更多相关文章

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

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

  2. Java反射机制以及动态代理

    Java反射机制以及动态代理 Java反射机制 含义与功能 Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类 ...

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

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

  4. Java基础系列 - 泛型和反射机制

    package com.test5; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Java泛型和反射机 ...

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

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

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

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

  7. java学习笔记13--反射机制与动态代理

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note13.html,转载请注明源地址. Java的反射机制 在Java运行时环境中,对于任意 ...

  8. Spring AOP中的JDK和CGLib动态代理哪个效率更高?

    一.背景 今天有小伙伴面试的时候被问到:Spring AOP中JDK 和 CGLib动态代理哪个效率更高? 二.基本概念 首先,我们知道Spring AOP的底层实现有两种方式:一种是JDK动态代理, ...

  9. Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题

    Spring AOP底层的动态代理实现有两种方式:一种是JDK动态代理,另一种是CGLib动态代理. JDK动态代理 JDK 1.3版本以后提供了动态代理,允许开发者在运行期创建接口的代理实例,而且只 ...

随机推荐

  1. 重构学习day01 类型码 类型码的上层建筑 与类型码相关的重构方法 1.使用子类代替类型码 2.使用状态或策略模式代替类型码

    名词:类型码 类型码的上层建筑 重构方法 1.使用子类代替类型码 2.使用状态/策略模式代替类型码 类中存在方法把某个字段当作条件,根据字段值的不同,进行不同的处理.(自定义概念)则这个字段叫做:类型 ...

  2. gns3 拖出设备显示一个红色的s,无法启动虚拟设备

    通过view-docks-调出console窗口,显示错误信息: Error while creating project: Can't connect to server http://172.0. ...

  3. exec 和 eval

    exec exec语句用来执行储存在字符串或文件中的Python语句, 我们可以运行一个包含Python语句的字符串 >>> exec "print 'Hello Pyth ...

  4. Web之localStorage

    localStorage: 1.localStorage拓展了cookie的4K限制 2.localStorage会可以将第一次请求的数据直接存储到本地,这个相当于一个5M大小的针对于前端页面的数据库 ...

  5. UVa10375:选择与除法(唯一分解定理)

    The binomial coefficient C(m,n) is defined as Given four natural numbers p, q, r, and s, compute the th ...

  6. 080 Remove Duplicates from Sorted Array II 从排序阵列中删除重复 II

    “删除重复项目” 的进阶:如果重复最多被允许两次,又该怎么办呢?例如:给定排序数列 nums = [1,1,1,2,2,3]你的函数应该返回长度为 5,nums 的前五个元素是 1, 1, 2, 2 ...

  7. C#私有的构造函数的作用

    C#私有的构造函数的作用:当类的构造函数是私有的时候,也已防止C1 c1=new C1();实例化类.常见的应用是工具类和单例模式. using System;using System.Collect ...

  8. java数据类型是有符号的,那与有些无符号的如何区别

    一.首先需要明白数据类型有符号与无符号的概念 最明显的区别就是二者表示的范围不同: 无符号数中,所有的位都用于直接表示该值的大小.有符号数中最高位用于表示正负,所以,当为正值时,该数的最大值就会变小. ...

  9. FXP登录Linux报错

    1.用FXP登录Linux报错: [info] subsystem request for sftp failed, subsystem not found.[右] [execute] /usr/li ...

  10. 借助Code Splitting 提升单页面应用性能

    近日的工作集中于一个单页面应用(Single-page application),在项目中尝试了闻名已久的Code splitting,收获极大,特此分享. Why we need code spli ...