注意:在调用 Class.forName()方法时, 没有在编译路径下(classpath)找到对应的类,那么将会抛出 ClassNotFoundException。// 加载指定的 Class 对象,参数 1 为要加载的类的完整路径 :包名+类名 ( 常用方式 ) public static Class<?> forName (String className) // 加载指定的 Class 对象,参数 1 为要加载的类的完整路径; // 参数 2
为是否要初始化该 Class 对象
,参数 3
为指定加载该类的 ClassLoader
. public static Class<?> forName (String className, boolean shouldInitialize, ClassLoader classLoader)
注意: 通过反射获取到 Constructor、Method、Field 后,在反射调用之前将此 对象的 accessible 标志设置为 true ,以此来提升反射速度。值为 true 则指示反射的对象在使用时 应该取消 Java 语言访问检查 。值为 false 则指示反射的对象应该实施 Java 语言访问检查。Constructor<?> constructor = clz.getConstructor(String.class); // 设置 Constructor 的 Accessible
constructor.setAccessible(true);
3 反射获取类中函数
// 获取 Class 对象中指定函数名和参数的函数,参数一为函数名,参数 2 为参数类型列表
public Method getDeclaredMethod (String name, Class...<?> parameterTypes)
// 获取该 Class 对象中的所有函数( 不包含从父类继承的函数 )
public Method[] getDeclaredMethods ()
// 获取指定的 Class 对象中的**公有**函数,参数一为函数名,参数 2 为参数类型列表
public Method getMethod (String name, Class...<?> parameterTypes)
// 获取该 Class 对象中的所有**公有**函数 ( 包含从父类和接口类集成下来的函数 )
public Method[] getMethods ()
注意: getDeclaredMethod 和 getDeclaredMethods 包含 private、protected、default、public 的函数,并且通过这两个函数获取到的只是在自身中定义的函数,从父类中集成的函数不能够获取到。而 getMethod 和 getMethods 只包含 public 函数,父类中的公有函数也能够获取到。
4 反射获取类中的属性
// 获取 Class 对象中指定属性名的属性,参数一为属性名
public Method getDeclaredField (String name)
// 获取该 Class 对象中的所有属性( 不包含从父类继承的属性 )
public Method[] getDeclaredFields ()
// 获取指定的 Class 对象中的**公有**属性,参数一为属性名
public Method getField (String name)
// 获取该 Class 对象中的所有**公有**属性 ( 包含从父类和接口类集成下来的公有属性 )
public Method[] getFields ()
5 反射获取指定类型的注解
// 获取指定类型的注解
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) ;
// 获取 Class 对象中的所有注解
public Annotation[] getAnnotations() ;
代理类在程序运行前不存在、运行时由程序动态生成的代理方式称为动态代理。
Java 提供了动态代理的实现方式,可以在运行时刻动态生成代理类。这种代理方式的一大好处是可以方便对代理类的函数做统一或特殊处理,
如记录所有函数执行时间、所有函数执行前添加验证判断、对某个特殊函数进行特殊操作,而不用像静态代理方式那样需要修改每个函数。
实现动态代理包括三步:
(1). 新建委托类;动态代理要求委托类必须实现了某个接口(该类是接口的实现类,接口中是要代理暴露在外的方法)
(2). 实现InvocationHandler
接口,这是负责连接代理类和委托类的中间类必须实现的接口;(要重写invoke()方法)
(3). 通过Proxy
类新建代理类对象。
主要的内部实现原理:
InvocationHandler
是负责连接代理类和委托类的中间类必须实现的接口。
public Object invoke(Object proxy, Method method, Object[] args)
函数需要去实现,参数:
proxy
表示 通过 Proxy.newProxyInstance() 生成的代理类对象
。
method
表示代理对象被调用的函数。
args
表示代理对象被调用的函数的参数。
调用代理对象的每个函数实际最终都是调用了InvocationHandler
的invoke
函数。
invoke
函数中可以通过对method
做一些判断,从而对某些函数特殊处理。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
loader
表示类加载器
interfaces
表示委托类的接口,生成代理类时需要实现这些接口
h
是InvocationHandler
实现类对象,负责连接代理类和委托类的中间类
可以这样理解,动态代理实现实际是双层的静态代理,开发者提供了委托类 B,程序动态生成了代理类 A。开发者还需要提供一个实现了InvocationHandler
的子类 C,子类 C 连接代理类 A 和委托类 B,它是代理类 A 的委托类,委托类 B 的代理类。用户直接调用代理类 A 的对象,A 将调用转发给委托类 C,委托类 C 再将调用转发给它的委托类 B。
b. 编译时动态处理,如动态生成代码
c. 运行时动态处理,如得到注解信息
1 标准 Annotation,Override, Deprecated, SuppressWarnings
标准 Annotation 是指 Java 自带的几个 Annotation,上面三个分别表示重写函数,不鼓励使用(有更好方式、使用有风险或已不在维护),忽略某项 Warning
2 元 Annotation,@Retention, @Target, @Inherited, @Documented
@Retention 保留时间,可选值 SOURCE(源码时),CLASS(编译时),RUNTIME(运行时),默认为 CLASS,SOURCE 大都为 Mark Annotation,这类 Annotation 大都用来校验,比如 Override, SuppressWarnings
@Target 可以用来修饰哪些程序元素,如 TYPE, METHOD, CONSTRUCTOR, FIELD, PARAMETER 等,未标注则表示可修饰所有
@Inherited 是否可以被继承,默认为 false