什么是反射?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
如果我们拿到一个类的类型信息,就可以利用反射获取其各种成员以及方法了.通过反射调用方法例子如下:
package com.reflection;
import java.lang.reflect.Method;
public class ReflectionAPI {
public static void main(String[] args) throws Exception {
Class<?>cla=Class.forName("java.lang.String");
/*
public Method[] getMethods()返回某个类的所有公用(public)方法包括其继
承类的公用方法,当然也包括它所实现接口的方法。
public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法,
包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所
实现接口的方法。
*/
//返回class对象所对应的类或接口中,所声明的所有方法的数组(包括私有方法)
Method[] method=cla.getDeclaredMethods();
//遍历输出所有方法声明
for(Method m:method){
System.out.println(m);
}
}
}
package com.reflect.method;
public class InvokeTest {
public int add(int id,int age){
return age;
}
public String reflect(String name){
return "hello:"+name;
}
}
package com.reflect.method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
//不用反射情况下,
InvokeTest it=new InvokeTest();
System.out.println(it.add(1, 10));
System.out.println(it.reflect("张三"));
System.out.println("---下面是使用反射的例子-----");
//使用反射首先获取类名
/*三种方式得到Class对象:
1.调用对象的getClass方法,返回该对象的Class对象 例如:String str = "aa"; Class<?> classType1 = str.getClass();
getClass()方法定义在Object类中,不是静态方法,需要通过对象来调用,
并且它声明 为final,表明不能被子类所覆写。
(Object方法有哪些。clone()、equals()、finalize()、getClass()、
面试官问过我这个问题。偶然想起了记录下来。)
2.Class.forName(“类的名字”);有个受查异常
如:Class.forName("java.lang.String");
3.Class c=类名.class 例如:String.class;
*/
Class<InvokeTest> cla=InvokeTest.class;
/*这里有必要提一下就是Class下的newInstance()和new有什么区别?,
首先,newInstance( )是一个方法,
* 而new是一个关键字,其次,Class下的newInstance()的使用有局限,
* 因为它生成对象只能调用无参的构造函数,
* 而使用new关键字生成对象没有这个限制。好,到此为止,我们总结如下:
* Class.forName("")返回的是类
* Class.forName("").newInstance()返回的是object.
*/
//这里生成新的对象,用newInstance()方法。
Object invokeTest=cla.newInstance();
System.out.println(invokeTest instanceof InvokeTest);
/*通过反射调用方法,首先需要获得与该方法相对应的Method对象。
*
*/
// 第一个参数是方法名,第二个参数是这个方法所需要的参数的Class对象的数组
Method method=cla.getMethod("add", new Class[]{int.class,int.class});
Method method2=cla.getMethod("reflect", new Class[]{String.class});
Object object=method.invoke(invokeTest, new Object[]{1,10});
System.out.println(object);
Object object2= method2.invoke(invokeTest, new Object[]{"反射"});
System.out.println(object2);
}
}
控制台输出结果:
10
hello张三
---下面是使用反射的例子-----
true
10
hello反射
/*********************java动态代理(JDK和cglib)*************************/
java动态代理主要涉及2个类:1.interface InvocationHandler;2.class Proxy .
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
静态代理:
package neusoft.proxy.dao;
public interface Count {
//查看账户的方法.
public void queryCount();
//修改账户的方法.
public void updateCount();
}
package neusoft.proxy.impl;
import neusoft.proxy.dao.Count;
public class CountImpl implements Count{
@Override
public void queryCount() {
System.out.println("**查询账户的方法**");
}
@Override
public void updateCount() {
System.out.println("**修改账户的方法**");
}
}
package neusoft.proxy.impl;
import neusoft.proxy.dao.Count;
//这是一个代理类(增强CountImpl实现类)
public class CountProxy implements Count{
private CountImpl countImpl;
//覆盖默认构造器
public CountProxy(CountImpl countImpl) {
this.countImpl = countImpl;
}
@Override
public void queryCount() {
//在这些方法里面增加一些业务逻辑,增强CountImpl实现类。
System.out.println("**事务处理之前**");
// // 调用委托类的方法;
countImpl.queryCount();
System.out.println("**事务处理之后**");
}
@Override
public void updateCount() {
System.out.println("**事务处理之前**");
// // 调用委托类的方法;
countImpl.updateCount();
System.out.println("**事务处理之后**");
}
}
package neusoft.proxy.test;
import neusoft.proxy.impl.CountImpl;
import neusoft.proxy.impl.CountProxy;
public class CountTest {
public static void main(String[] args) {
CountImpl countImpl=new CountImpl();
CountProxy countProxy=new CountProxy(countImpl);
countProxy.queryCount();
countProxy.updateCount();
}
通过这些代码可以发现,CountProxy 代理类只能为Count这一个接口服务,这样必然会产生过多的代理,对比下面的动态代理差别就一目了然了。
JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。
Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class
package neusoft.proxy.dao;
public interface MyProxy {
public void add();
//我们再添加一个方法;
public void delete();
}
package neusoft.proxy.impl;
import neusoft.proxy.dao.MyProxy;
public class MyProxyImpl implements MyProxy{
@Override
public void add() {
System.out.println("-----add方法---------------");
}
@Override
public void delete() {
System.out.println("-----delete方法--------");
}
}
package neusoft.proxy.impl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//这是一个代理类(增强MyProxyImpl实现类)
public class MyDynamicProxy implements InvocationHandler{
private Object pro;
public MyDynamicProxy(Object obj){
this.pro=obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
doBefore(method);
System.out.println(proxy.getClass().getSimpleName());
Object result= method.invoke(pro, args);
return result;
}
public static void doBefore(Method method){
System.out.println(method.getName()+"方法执行*****doBefore******");
}
}
package neusoft.proxy.test;
import java.lang.reflect.Proxy;
import neusoft.proxy.dao.MyProxy;
import neusoft.proxy.impl.CountProxy;
import neusoft.proxy.impl.MyDynamicProxy;
import neusoft.proxy.impl.MyProxyImpl;
public class MyDynamicProxyTest {
public static void main(String[] args) {
//得到MyProxy接口的一个实例对象.
MyProxy impl=new MyProxyImpl();
/*
* 在java中实现动态代理步骤:
* 1,由前面的静态代理可知,有一个接口,一个接口的实现类,而这个实现类就是我们要代理的对象。
* 所谓代理就是在调用实现类的方法时,可以在方法执行前后做额外的工作,这个就是代理。
* 2,我们要自己写一个在要代理类的方法执行时,能够做额外工作的类,而这个类必须继承InvocationHandler接口,
* 为什么要继承它呢?因为代理类的实例在调用实现类的方法的时候,不会调真正的实现类的这个方法,
* 而是转而调用这个类的invoke方法(继承时必须实现的方法),在这个方法中你可以调用真正的实现类的这个方法。
在要用代理类的实例去调用实现类的方法的时候,写出下面两段代码。
*/
MyProxy proxy=(MyProxy)Proxy.newProxyInstance(impl.getClass().getClassLoader(),
impl.getClass().getInterfaces(),
new MyDynamicProxy(impl));
/*
* 第一,根据impl.getClass().getClassLoader()这个要代理类的类加载器和
* impl.getClass().getInterfaces()要代理类所实现的所有的接口 impl.getClass().getInterfaces()=new Class[]{MyProxy.class};
* 作为参数调用Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces)
* 的方法返回代理类的java.lang.Class对象,也就是得到了java动态生成的代理类$Proxy0的Class对象。
* 同时,java还让这个动态生成的$Proxy0类实现了要代理类的实现的所有接口,并继承了Proxy接口。
* 第二,实例化这个动态生成的$Proxy0类的一个实例,实例化代理类的构造函数为Proxy(InvocationHandler h),
* 也就是说要实例化这个动态生成的$Proxy0类,必须给它一个InvocationHandler参数,也就是我们自己实现的用来在代理类
* 方法执行前后做额外工作的类MyDynamicProxy。
* 这段代码Proxy.newProxyInstance(impl.getClass().getClassLoader(),impl.getClass().getInterfaces(),new MyDynamicProxy(impl))
* 得到的其实是一个类名叫$Proxy0 extends Proxy implements MyProxy的类。
* 第三,将这个$Proxy0类强制转型成MyProxy类型,调用add方法。
*/
proxy.add();
proxy.delete();
}
}
输出结果:
add方法执行*****doBefore******
$Proxy0
-----add方法---------------
接口加上delete方法后,输出结果:
add方法执行*****doBefore******
$Proxy0
-----add方法---------------
delete方法执行*****doBefore******
$Proxy0
-----delete方法----
可以看到我们自己加的代理业务逻辑执行了2遍。