反射概念
正常的关于对象的处理流程是根据包名.类名找到类,所谓的"反"指的是根据对象来取得对象的来源信息,而这个"反"的操作核心的处理就在于Object类的一个方法:
该方法返回的是一个Class类对象,这个Class描述的就是类
三种获取某个类Class对象的方式
通过类对象获取该类实例
反射调用构造方法
在定义简单java类的时候一定要保留有一个无参构造,Class类通过反射实例化类对象的时候,只能够调用类中的无参构造。
如果现在类中没有无参构造则无法使用Class 类调用,只能够通过明确的构造调用实例化处理
反射调用普通方法
//取得全部普通方法:
public Method[] getMethods() throws SecurityException
//取得指定普通方法:
public Method getMethod(String name, Class<?>... parameterTypes)
//以上两个方法范辉的类型是java.lang.reflect.Method类的对象,在此类中提供有一个调用方法的支持:
public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetExceptio
反射调用类中属性
-
父类中
取得父类中的所有属性
取得父类中指定名称的属性
-
本类中
取得本类中的所有属性
取得本类中指定名称的属性
反射与代理模式
代理设计模式的核心本质在于:一个接口有两个子类,一个负责真实业务,一个负责与真实业务有关的所有辅助性操作。
package review822.proxy;
import java.lang.reflect.Constructor;
interface ISubject { // 核心操作接口
public void eat(); // 吃饭是核心业务
}
class RealSubject implements ISubject {
@Override
public void eat() {
System.out.println("饿了要吃饭");
}
}
class ProxySubject implements ISubject {
private ISubject subject;
public ProxySubject(ISubject subject) {
this.subject = subject;
}
public void prepare() {
System.out.println("饭前准备");
}
public void afterEat() {
System.out.println("饭后拾掇");
}
@Override
public void eat() {
this.prepare();
this.subject.eat(); // 核心吃
this.afterEat();
}
}
class Factory {
private Factory() {
}
public static <T> T getInstance(String className) {
T t = null;
try {
t = (T) Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return t;
}
public static <T> T getInstance(String proxyClassName, String realClassName) {
T t = null;
try {
// 取得真实接口对象
T realObj = getInstance(realClassName);
Constructor<?> cons = Class.forName(proxyClassName).getConstructor(realObj.getClass().getInterfaces()[0]);
t = (T) cons.newInstance(realObj);
} catch (Exception e) {
e.printStackTrace();
}
return t;
}
}
public class TestDemo {
public static void main(String[] args) {
ISubject subject2 = Factory.getInstance("review822.proxy.ProxySubject","review822.proxy.RealSubject") ;
subject2.eat();
}
}
以上代理模式的不足之处在于,在开发中并不知道项目会有多少个接口,如果这些接口都需要使用到代理模式,那么就意味着每一个接口都需要编写两个子类,再假设这些接口的代理类的功能几乎都一样。
要想解决此问题,需要引入动态代理设计模式。
动态代理
动态代理模式的核心特点:一个代理类可以代理所有需要被代理的接口的子类对象
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface ISubject { // 核心操作接口
public void eat(String msg, int num); // 吃饭是核心业务
}
class RealSubject implements ISubject {
@Override
public void eat(String msg, int num) {
System.out.println("我要吃 " + num + "分量的 " + msg);
}
}
/**
* 动态代理类
* 动态代理实现的标识接口,只有实现此接口才具备有动态代理的功能
*/
class ProxySubject implements InvocationHandler {
// 绑定任意接口的对象,使用Object描述
private Object target;
/**
* 实现真实对象的绑定处理,同时返回代理对象
* @param target
* @return 返回一个代理对象(这个对象是根据接口定义动态创建生成的代理对象)
*/
public Object bind(Object target) {
// 保存真实主题对象
this.target = target;
/**
* 如果要想进行对象的绑定,那么就需要使用一个Proxy程序类,这个程序类的功能是可以绑定所有需要绑定的接口
* 子类对象,而且这些对象都是根据接口自动创建的,该类有一个动态创建绑定对象的方法:
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public void preHandle() {
System.out.println("[ProxySubject] 方法处理前");
}
public void afterHandle() {
System.out.println("[ProxySubject] 方法处理后");
}
/**
* invoke表示的是调用执行的方法,但是所有的代理类返回给用户的接口对象都属于代理对象
* 当用户执行接口方法的时候所调用的实例化对象就是该代理主题动态创建的一个接口对象
* @param proxy 表示被代理的对象信息
* @param method 返回的是被调用的方法对象,取得了Method对象则意味着可以使用invoke()反射调用方法
* @param args 方法中接收的参数
* @return 方法的返回值
* @throws Throwable 可能产生的异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.preHandle();
// 反射调用方法
Object ret = method.invoke(this.target, args);
this.afterHandle();
return ret;
}
}
public class TestDemo {
public static void main(String[] args) {
ISubject subject = (ISubject) new ProxySubject().bind(new RealSubject());
subject.eat("鱼香肉丝", 66);
}
}