Java反射与动态代理
Java反射机制可以动态地获取类的结构,动态地调用对象的方法,是java语言一个动态化的机制。java动态代理可以在不改变被调用对象源码的前提下,在被调用方法前后增加自己的操作,极大地降低了模块之间的耦合性。这些都是java的基础知识,要想成为一名合格的程序猿,必须掌握!
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制允许程序在运行时判断分析任意一个类的结构,包括成员变量和方法,并调用任意一个对象的方法。Eclipse可以自动弹出对象的方法及属性,就是利用了反射的原理。Java的动态代理就是利用了反射的特性来实现的。
1、获取类Class对象
1) A.class :不会加载类,也不会执行静态代码段;
2) Class.forName("cn.test.reflect.A") :要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段;
3) new A().getClass() :通过对象获取class
2、反射创建对象
1) 通过默认构造函数创建对象:Class<?> t = Class.forName("cn.test.reflect.A"); t.newInstance();
2) 通过指定构造函数创建对象:Class<?> t = Class.forName("cn.test.reflect.A"); Constructor<?> cons[] = t.getConstructors(); A a = (A) cons[2].newInstance("aa","bb");
注:
① Class<?>表示任何类型的类;
② newInstance()方法只能调用public的无参构造函数,它和new关键字创建实例的区别:创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类;
3、Class类常用方法
▶ getName() :获得类的完整名字;
▶ getSuperclass() :获得类的父类;
▶ newInstance() :通过类的不带参数的构造方法创建这个类的一个对象;
▶ getFields() :获得当前类和父类中的public类型的所有属性;
▶ getDeclaredFields() :获得当前类(不包含父类)声明的所有属性,包括private和public;
注:对于某个属性field,设置field.setAccessible(true),即可访问private的属性值,如field.get(obj)
▶ getMethods() :获得前类和父类中public类型的所有方法;
▶ getDeclaredMethods() :获得当前类(不包含父类)声明的所有方法,包括private和public;
▶ getMethod(String name, Class[] parameterTypes) :获得类的指定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型;
▶ getConstructors() :获得当前类的public类型的构造方法;
▶ getDeclaredConstructors() :获得当前类的public和private类型的构造方法;
▶ getConstructor(Class[] parameterTypes) :获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型;
▶ getInterfaces() :获得实现的接口;
▶ getSuperclass() :获得继承的父类;
4、Java反射使用实例
package com.hicoor.test.reflect; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter; class B{
public int b;
public B(){}
} interface IA{} class A extends B implements IA{
public A() { } public A(String str) { } public A(String str1, String str2) { } private String str;
public int age; public int func1(String name) {
System.out.println("hello " + name);
return 8;
} public void func1(String name1, String name2) {
System.out.println("hello "+name1+","+name2);
}
} public class ReflectDemo { public static void main(String[] args) throws Exception {
// 根据字符串获得类
Class<?> demoClass = Class.forName("com.hicoor.test.reflect.A"); // 获得类的完整名字
System.out.println("类名"+demoClass.getName()); // com.hicoor.test.reflect.A
// 获得类加载器,默认sun.misc.Launcher$AppClassLoader
System.out.println("类加载器:"+demoClass.getClassLoader().getClass().getName()); //根据Class的共有无参构造方法创建一个实例
A newAObj = (A)demoClass.newInstance(); // 获得类中声明的属性
Field[] publicFields = demoClass.getFields(); // 获得当前类和父类中的public类型的所有属性,返回:age
Field[] declareFields = demoClass.getDeclaredFields(); // 获得当前类(不包含父类)声明的所有属性,包括private和public,返回:str age
Field specifyField = demoClass.getField("age"); // 根据名称获取指定属性
specifyField.setAccessible(true);
//修改属性
specifyField.set(newAObj, 88); // 获得类的方法
Method[] publicMethods = demoClass.getMethods(); // 获得前类和父类中public类型的所有方法
Method[] declareMethods = demoClass.getDeclaredMethods(); // 获得当前类(不包含父类)声明的所有方法,包括private和public
Method specifyMethod = demoClass.getDeclaredMethod("func1",new Class<?>[]{java.lang.String.class}); //根据方法名和方法参数类型指定获取一个方法
//反射调用对象的方法
specifyMethod.invoke(newAObj, "hans"); //获得构造函数
Constructor<?>[] publicConstructors = demoClass.getConstructors();
Constructor<?>[] declareConstructors = demoClass.getDeclaredConstructors(); //获得当前类声明的所有private和public构造方法
Constructor<?> constructor = demoClass.getConstructor(new Class<?>[]{java.lang.String.class}); //根据指定类型获得构造方法
A newAobj2 = (A)constructor.newInstance("hello"); //根据指定构造函数创建实例 //获得实现的接口
Class<?>[] interfaces = demoClass.getInterfaces(); //获得继承的父类
Class<?> superclass = demoClass.getSuperclass();
} //反射获得一个方法的明细定义
private static void getMethodDetail(Method method) {
String methodModifier = Modifier.toString(method.getModifiers()); //方法修饰符
String returnType = method.getReturnType().getName(); //方法返回值
Class<?>[] parameterTypes = method.getParameterTypes(); //方法参数类型
System.out.print(methodModifier+" "+returnType+" "+ method.getName()+"(");
int i=1;
for (Class<?> parameterType : parameterTypes) {
System.out.print(parameterType.getName() + " arg"+(i++));
if(i<=parameterTypes.length){
System.out.print(",");
}
}
System.out.println(") {}");
} }
假如有这样的需求,要在某些模块方法调用前后加上一些统一的前后处理操作,比如在添加购物车、修改订单等操作前后统一加上登陆验证与日志记录处理,该怎样实现?首先想到最简单的就是直接修改源码,在对应模块的对应方法前后添加操作。如果模块很多,你会发现,修改源码不仅非常麻烦、难以维护,而且会使代码显得十分臃肿。
这时候就轮到动态代理上场了,它可以通过反射在被调用方法前后加上自己的操作,而不需要更改被调用类的源码,大大地降低了模块之间的耦合性,体现了极大的优势。
1、JDK动态代理
JDK动态代理中包含一个类和一个接口,即Proxy类和InvocationHandler接口。
1) InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:① Object proxy:指被代理的对象;② Method method:要调用的方法;③ Object[] args:方法调用时所需要的参数;
2) Proxy类: Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
参数说明:① ClassLoader loader:类加载器;② Class<?>[] interfaces:得到全部的接口;③ InvocationHandler h:得到InvocationHandler接口的子类实例 ;
3) 关于类加载器
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有以下三种类加载器:
① Booststrap ClassLoader:此加载器采用C++编写,通常加载jre/lib/rt.jar,一般开发中是看不到的;
② Extendsion ClassLoader:用来进行扩展类的加载,通常加载jre/lib/ext/*.jar;
③ AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器;
4) JDK动态代理实例:
package com.hicoor.test.dynamicProxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; interface Animal {
public void makeSound(String name);
} class Dog implements Animal {
@Override
public void makeSound(String name) {
System.out.println("Hi," + name + ",wang,wang~~");
}
} class Cat implements Animal {
@Override
public void makeSound(String name) {
System.out.println("Hi," + name + ",miao,miao~~");
}
} /**
* @author Hans 通用动态代理类,被调用对象方法前后增加特殊操作一样的类可都用此类代理
*/
class AnimalProxy implements InvocationHandler {
// 要代理的对象
private Object target; /**
* 绑定委托对象并返回一个代理类
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
// 取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
System.out.println("方法调用前操作..");
// 执行被调用方法主体
result = method.invoke(target, args);
System.out.println("方法调用后操作..");
return result;
} } public class DynamicProxyJDKDemo {
public static void main(String[] args) {
AnimalProxy proxy = new AnimalProxy();
Animal dogProxy = (Animal) proxy.getInstance(new Dog());
dogProxy.makeSound("Tom");
}
}
2、Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
使用cglib代理需下载cglib.jar文件,下载地址:http://www.java2s.com/Code/Jar/c/Downloadcloudcglibjar.htm
Cglib动态代理实例:
package com.hicoor.test.dynamicProxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; class Snake{
public void makeSound(String name) {
System.out.println("Hi," + name + ",si,si~~");
}
} class AnimalProxyCglib implements MethodInterceptor {
// 要代理的对象
private Object target; /**
* 创建代理对象
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
} @Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
Object result = null;
System.out.println("方法调用前操作..");
// 执行被调用方法主体
result = proxy.invokeSuper(obj, args);
System.out.println("方法调用后操作..");
return result;
} } public class DynamicProxyCglibDemo { public static void main(String[] args) {
AnimalProxyCglib proxy = new AnimalProxyCglib();
Snake dogProxy = (Snake) proxy.getInstance(new Snake());
dogProxy.makeSound("Tom");
} }
Java反射与动态代理的更多相关文章
- Java反射和动态代理
Java反射 反射机制 RTTI 编译器在编译时打开和检查*.class文件 反射机制 运行时打开和检查*.class文件 Java反射常见的方法 java反射的应用 setAccessible(bo ...
- Java 反射 设计模式 动态代理机制详解 [ 转载 ]
Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...
- Java反射机制动态代理
1.什么事反射机制动态代理 在一段代码的前后动态执行其他操作,比如有一个方法是往数据库添加一个记录,我们可以通过动态代理,在操作数据库方法的前和后添加代码执行打开数据库连接和关闭数据库连接. 2.演示 ...
- java反射和动态代理实现与原理详细分析
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式 代理模式是常用的java设计模式, ...
- java反射实现动态代理
参考:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html http://my.oschina.net/lyp3314/b ...
- Java反射 - 3(动态代理)
动态代理是对包装模式的升级,可以动态的传入需要代理的对象实现代理 准备如下 1. 被代理类的接口 2.被代理类 3.处理器:InvocationHandler 4.代理调用:Proxy.newInst ...
- Java 反射之动态代理
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt205 利用Java反射机制你可以在运行期动态的创建接口的实现.java.la ...
- java反射与动态代理的理解
一.什么是反射机制? 反射的官方定义是这样的:在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息及动态调用类对象 ...
- java反射以及动态代理的学习
java反射学习 1)字节码文件的三种获取方式 ①:Object类的getClass()方法:对象.getClass() ②:数据类型的静态的class属性:类名.class ③:通过Class类的静 ...
随机推荐
- [BZOJ1072][SCOI2007] 排列prem
Description 给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0).例如123434有90种排列能被2整除,其中末位为2的有30种,末位为4的有60种. Input ...
- package XXX.i386.rpm is not installed(检查在Linux上安装Oracle所需的pkg时)
如下转自一个论坛,忘了哪了,一直在电脑上存的. I've got Oracle Enterprise Linux 5 to install an Oracle server. Checking req ...
- 【POJ】1811 Prime Test
http://poj.org/problem?id=1811 题意:求n最小素因子.(n<=2^54) #include <cstdio> #include <cstring& ...
- Invalid escape sequence(valid ones are \b \t \n \f \r \" \' \\)
Invalid escape sequence(valid ones are \b \t \n \f \r \" \' \\) 在运行eclipse的相关程序代码时遇到了报错信息,查看控制台 ...
- Node.js的DES加解密和MD5加密
最基本的就是经常用的md5加密算法 代码如下 var MD5=function (data) { var _encrymd5 = require('crypto').createHas ...
- webdriver中PDF控件无法显示的问题(IE兼容性)
公司的的系统只能运行在32位的IE上,开始从http://selenium-release.storage.googleapis.com/index.html?path=2.48/ 这个路径下去下载了 ...
- 浅析Spring中的注解
Spring的配置,通常有两种:使用配置文件和注解.那么Spring如何知道各个Bean或者Service.Controller以及Bean中各类属性之间的关系呢?答案肯定是在定义各个Java文件的时 ...
- UniversalAndroidImageLoader出现异常:ImageLoader: Unable to resolve host "https": No address associated with host
问题描述 使用ImageLoader时,出现如下错误,始终加载图片错误,显示img_error的图片.UniversalAndroidImageLoader出现异常:ImageLoader: Unab ...
- HTTP协议 (六) 状态码详解
HTTP协议 (六) 状态码详解 HTTP状态码,我都是现查现用. 我以前记得几个常用的状态码,比如200,302,304,404, 503. 一般来说我也只需要了解这些常用的状态码就可以了. 如果 ...
- 执行JDBC的executeUpdate()方法时,报错:数据类型不一致,应为number,但却为binary
该原因是因为,在拼写update语句的时候将一个number类型的字段的值赋为了null导致的,如果想将一个number类型的字清空,不能使用null,可以使用“”来替代.