概念
能够分析类能力的程序称为反射。
用处
1、在运行时分析类的能力。
2、实现动态代理
3、读取配置
通过反射我们可以知道在运行时得到类的相关信息进行分析。
原理
Class类
在程序运行期间,Java运行时系统始终为所有对象维护一个运行时类型标识。这个信息会跟踪每个对象所属的类。虚拟机利用运行时类型信息选择要执行的正确方法。不过,可以使用一个特殊的Java类访问这些信息。保存这些信息的类名为Class。
获取Class类的三种方法
1.Class.forName(全类名)
2.对象.getClass()
3.类名.class
API
static Class forName(String className)
返回一个Class对象,表示名为className的类。
Constructor getConstructor(Class … parameterTypes)
生成一个对象,描述有指定参数类型的构造器。
Field[] getFields()
Field[] getDeclaredFields()
getFields返回一个包含Field对象的数组,包含这个类或其超类的公共字段。getDeclaredFields返回这个类的全部字段。
Constructor [] getConstructors()
Constructor [] getDeclaredConstructors()
getConstructors返回一个包含Constructor 对象的数组,包含这个类或其超类的公共构造方法。getDeclaredConstructors返回这个类的全部构造方法。
Method[] getMethods()
Method[] getDeclaredMethods()
getMethods返回一个包含Method对象的数组,包含这个类或其超类的公共方法。getDeclaredMethods返回这个类的全部方法。
反射机制最重要的内容----检查类的结构。共有三个类,Field、Method、Constructor。
Constructor 类的构造方法
API
Object newInstance(Object… params)
将params传递到构造器,来构造这个构造器声明类的一个新实例
Constructor 类的构造方法、 Field 字段、Method 方法
API
Class getDeclaredClass()
返回一个Class对象,表示定义了这个构造器、方法或字段的类。
Class[] getExceptionTypes()(在Construcotr和Method classes类中)
返回一个Class对象数组,表示抛出异常的类型。
int getModifiers()
返回一个整数,描述这个构造器、方法和字段的修饰符。使用Modifier类中的方法分析这个返回值。
String getName()
返回名称
Class[] getParameterTypes()(在Construcotr和Method classes类中)
返回一个Class对象数组,其中各个对象表示参数的类型。
Class getReturnType() (在Method类中)
表示返回值的类型
Void setAccessible(boolean f)
设置访问权限
Java动态代理
静态代理需要为每个被代理类创建一个代理类,因此被代理类必须事先定义好。而动态代理可以代理任意实现了接口的类。
JDK动态代理只能对实现了接口的类进行代理。(为什么后文会讲)
动态代理过程
首先定义一个接口
public interface Calculator {
int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int div(int a, int b);
}
实现类
public class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) {
System.out.println(a+b);
return a+b;
}
@Override
public int sub(int a, int b) {
return a-b;
}
@Override
public int mul(int a, int b) {
return a*b;
}
@Override
public int div(int a, int b) {
return a/b;
}
}
我们首先定义一个类实现InvocationHandler接口,将要代理的对象通过构造方法传入,并实现invoke方法。
public class MyProxyHandler implements InvocationHandler {
//要代理的对象
private Calculator target;
public MyProxyHandler(Calculator h) {
this.target = h;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取参数
System.out.println("beginWith---方法的参数是--" + Arrays.asList(args));
before();
Object result = method.invoke(target,args);
after();
return result;
}
/**
* 前置
*/
public void before() {
System.out.println("before---");
}
/**
* 后置
*/
public void after() {
System.out.println("after---");
}
}
test:
/**
* jdk动态代理测试
*
*/
public class Test {
public static void main(String[] args) {
Calculator target = new CalculatorImpl();
Calculator proxy = (Calculator) Proxy.newProxyInstance(Calculator.class.getClassLoader(),
new Class<?>[]{Calculator.class},
new MyProxyHandler(target));
proxy.add(1, 2);
}
}
经过动态代理最终得到的代理类是下面这样的。
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import me.mingshan.dy.Calculator;
public final class $Proxy0 extends Proxy implements Calculator {
private static Method m1;
private static Method m2;
private static Method m5;
private static Method m3;
private static Method m4;
private static Method m6;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int mul(int var1, int var2) throws {
try {
return ((Integer)super.h.invoke(this, m5, new Object[]{Integer.valueOf(var1), Integer.valueOf(var2)})).intValue();
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final int add(int var1, int var2) throws {
try {
return ((Integer)super.h.invoke(this, m3, new Object[]{Integer.valueOf(var1), Integer.valueOf(var2)})).intValue();
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final int sub(int var1, int var2) throws {
try {
return ((Integer)super.h.invoke(this, m4, new Object[]{Integer.valueOf(var1), Integer.valueOf(var2)})).intValue();
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final int div(int var1, int var2) throws {
try {
return ((Integer)super.h.invoke(this, m6, new Object[]{Integer.valueOf(var1), Integer.valueOf(var2)})).intValue();
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m5 = Class.forName("me.mingshan.dy.Calculator").getMethod("mul", new Class[]{Integer.TYPE, Integer.TYPE});
m3 = Class.forName("me.mingshan.dy.Calculator").getMethod("add", new Class[]{Integer.TYPE, Integer.TYPE});
m4 = Class.forName("me.mingshan.dy.Calculator").getMethod("sub", new Class[]{Integer.TYPE, Integer.TYPE});
m6 = Class.forName("me.mingshan.dy.Calculator").getMethod("div", new Class[]{Integer.TYPE, Integer.TYPE});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
可以看到代理后生成的对象包含代理对象的方向,并使用自定义invoke方法进行了增强。原理就是使用反射获取代理对象的方法进行调用增强。那么为什么JDK动态代理必须要实现接口?
首先我们得知道为什么有动态代理?他和静态代理有什么区别?
动态代理和静态代理的区别
1.静态代理只能代理一个确定的类,动态代理可以代理一个接口下的多个类。
2.静态代理必须知道代理哪一个类,在程序运行前就已经完成代理。动态代理是在运行时才知道代理什么类。
所以动态代理的出现是因为静态代理每次只能代理一个类,在需要对多个类同时进行代理时就会出现很多重复开发,动态代理就是为了实现多个类的代理出现的。
JDK动态代理为什么只能代理实现了接口的类
1.动态代理是为了实现对多个类或者说多个方法的代理,且代理对象是运行时生成的,我们编写代码时并不知道代理对象是什么,所以我们只能用被代理对象来接收。
2.被代理对象能被接收,在Java中有两种方法实现,一种是继承,一种是实现接口。
3.Java中只能单继承。JDK动态 代理自动生成对的类$Proxy0继承了java.lang.reflect.Proxy类,由于java是单继承的,所以这里没有机会再去继承被代理类。
4.性能问题,反射的性能很差。那么假如java.lang.reflect.Proxy设计为接口,那么就能对类进行继承实现动态代理了。但是这样就得反射两次了,继承被代理对象后,首先要反射获得前置增强逻辑,然后super调用原逻辑,再反射获得后置增强逻辑。