一、反射:
-
反射的概念:动态加载对象,并对对象进行剖析。在Java中的反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制
-
反射的功能:利用Java反射机制我们可以加载一个运行时才得知名称的class,获悉其构造方法,并生成其对象实体,能对其fields设值并唤起其methods。
-
在运行时判断任意一个对象所属的类
-
在运行时构造任意一个类的对象
-
在运行时判断任意一个类所具有的方法和属性
-
在运行时调用任意一个对象的方法
-
-
在Java中我们有三种方法可以获取一个对象的反射类:
-
通过getClass方法
在Java中,每一个
Object
都有一个getClass
方法,通过getClass方法我们可以获取到这个对象对应的反射类:String s = "ziwenxie"; Class<?> c = s.getClass();
-
通过forName方法
Class<?> c = Class.forName("java.lang.String");
-
使用.class
Class<?> c = String.class;
-
-
应用场合:在Java程序中许多对象在运行时都会出现两种类型:编译时类型和运行时类型
编译时的类型由声明该对象时使用的类型决定,运行时的类型由实际赋给对象的类型决定
如:Person p =new Student();
编译时类型为Person,而运行时为Student -
JAVA反射API
反射API用来生成在当前JAVA虚拟机中的类、接口或者对象的信息。
Class类:反射的核心类,可以获取类的属性,方法等内容信息。
Field类:Java.lang.reflect.表示类的属性,可以获取和设置类的中属性值。
Method类:Java.lang.reflect。表示类的方法,它可以用来获取类中方法的信息或者执行方法
Construcor类:Java.lang.reflect。表示类的构造方法。 -
应用:Struts2配置action,spring的bean注入
二、动态代理
首先,代理是一个机制,在代理模式中,代理可以看作是对调用目标的一个包装,这样我们对目标代码的调用不是直接发生的,而是通过代理完成。
通过代理可以让代码之间解耦,比如RPC调用,框架内部的寻址、序列化、反序列化等,对于调用者往往是没有太大
意义的,通过代理,可以提供更加友善的界面。下面看一个列子:
public class MyDynamicProxy {
public static void main (String[] args) {
HelloImpl hello = new HelloImpl();
MyInvocationHandler handler = new MyInvocationHandler(hello);
// 构造代码实例
Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler);
// 调用代理方法
proxyHello.sayHello();
}
}
interface Hello {
void sayHello();
}
class HelloImpl implements Hello {
@Override
public void sayHello() {
System.out.println("Hello World");
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("Invoking sayHello");
Object result = method.invoke(target, args);
return result;
}
}
上面的代码中,简单实现了动态代理的构建和代理操作。首先,实现了InvocationHandler接口,这个接口里面只有invoke这个方法,每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
//proxy: 指代我们所代理的那个真实对象
//method: 指代的是我们所要调用真实对象的某个方法的Method对象
//args: 指代的是调用真实对象某个方法时接受的参数
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
然后主要是以Hello这个接口为纽带,为被调用目标构建代理对象,进而应用程序就可以使用代理对象间接运行调用目标的逻辑,代理为应用插入额外逻辑(这里是 println)提供了便利的入口。可以在invoke方法实现中增加自定义的逻辑实现,实现对被代理类的业务逻辑无侵入。
这种实现方式很有局限性,它是以接口为中心的,相当于添加了一种对于被调用者没有太大意义的限制。主要看看spring中的JDK动态代理和cglib动态代理。这两者的主要区别是,JDK动态代理主要是创建接口的动态代理,而cglib主要是创建目标类的子类的方式。