注解反射动态代理的简单学习
一.注解
java中注解默认实现annotation接口,一般我们自定义注解的时候主要使用的是两个元注解(其他两个@Documented 与 @Inherited基本没怎么使用过)看下面
1.@Target
主要限制可以应用注解的java元素类型
ElementType.ANNOTATION_TYPE 可以应用于注解类型。
ElementType.CONSTRUCTOR 可以应用于构造函数。
ElementType.FIELD 可以应用于字段或属性。
ElementType.LOCAL_VARIABLE 可以应用于局部变量。
ElementType.METHOD 可以应用于方法级注解。
ElementType.PACKAGE 可以应用于包声明。
ElementType.PARAMETER 可以应用于方法的参数。
ElementType.TYPE 可以应用于类的任何元素。
2.@Retention
RetentionPolicy.CLASS
RetentionPolicy.SOURCE
RetentionPolicy.RUNTIME
RetentionPolicy.CLASS
仅仅保留在源码中,被编译器忽略,主要应用场景是apt技术,在编译期能够获取注解与注解声明的类包括类中所有成员信息,一般用于生成额外的辅助类。还有语法检查,类似@IntDef这种
RetentionPolicy.SOURCE
会被编译器保留,但是会被jvm忽略,用处主要是用在字节码增强技术,在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解。
RetentionPolicy.RUNTIME
用的比较多,主要是通过反射技术动态获取注解元素
简单应用
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface lengthTest {
int max() default 0;
int min() default 0;
String dec() default "";
}
public class AnnLoginModel {
private int age;
@lengthTest(max = 10,min = 6,dec = "kkk")
private String desc;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
public static void vaild(Object o) throws Exception{
Class<?> ls = o.getClass();
Field[] fields = ls.getDeclaredFields();
for (Field field:fields) {
lengthTest lengthTest = field.getAnnotation(lengthTest.class);
if(lengthTest!=null){
if(field.getGenericType().toString().equals("class java.lang.String")){
field.setAccessible(true);
String i = (String) field.get(o);
if(i.length()>lengthTest.min()&&i.length()< lengthTest.max()){
System.out.print("没超过");
}else{
System.out.print("超过");
}
}
}
}
}
public static void main(String[] args) throws Exception {
AnnLoginModel annLoginModel = new AnnLoginModel();
annLoginModel.setAge(2);
annLoginModel.setDesc("傻子");
vaild(annLoginModel);
}
这是注解加反射进行参数校验的简单例子
二.反射
反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和
方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。是Java被视为动态语言的关键。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int value();
}
activity中
@ViewInject(R.id.bt)
Button bt;
@ViewInject(R.id.tv)
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_annotation);
MyViewInject.ViewInject(this);
}
public static void ViewInject(Activity activity) {
Class<? extends Activity> ls = activity.getClass();
for (Field field : ls.getDeclaredFields()) {
ViewInject an = field.getAnnotation(ViewInject.class);//判断是否是viewinject注解
if (an != null) {
try {
field.setAccessible(true);//设置访问权限,应许操作private的属性
Method method = ls.getDeclaredMethod("findViewById", int.class);//拿取activity的findviewbyid方法,当然你也可以直接使用ls.findviewbyid
View view = (View) method.invoke(activity, an.value());//method(ac,an.value)第一个参数在哪个对象上设置调用,第二个参数方法的参数
field.set(activity, view);//反射字段属性赋值
} catch (Exception e) {
}
}
}
简单例子
1.获取class
一般可以通过类名,对象获取
2.创建实例
可以通过class对象的newinstance,或者构造方法constructor.newInstance
其他方法懒的介绍有点多
3.反射的缺点
Method#invoke 需要进行自动拆装箱
反射需要按照名检索方法和参数,需要检查方法可见性参数一致性,编译器无法对动态调用的代码做优化,比如内联
三.动态代理,静态代理
1.静态代理
一般都是定义一个接口,一个对象实现接口,新建个代理对象,对对象进行控制管理。简单来说通过引入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性。
静态代理缺点,一般代理对象和对象是一对一关系,一对一则会出现时静态代理对象量多、代码量大,从而导致代码复杂,可维护性差的问题,一对多则代
理对象会出现扩展能力差的问题。
2.动态代理
JDK提供了 Proxy 来完成这件事情,其实就是在运行期动态创建了一个class,然后通过反射创建method,通过
InvocationHandler回调出去
image.png
简单例子
ListenerInvocationHandler invocationHandler = new ListenerInvocationHandler(activity,method);//activity当前activity对象,就是哪里调用onclick方法
Object proxyInstance = Proxy.newProxyInstance(activity.getClassLoader(), new Class[]{clickClass}, invocationHandler);//把onclick方法交给invocation处理
for (int id : ids) {
View view = activity.findViewById(id);
Method setter = view.getClass().getMethod(str, clickClass);//获取onclick方法
setter.invoke(view, proxyInstance);//使用动态代理,setter就是系统的onclick方法view就是注解的控件id,proxyinstance就是代理类,代理类就是activity写的onclick方法
}
public class ListenerInvocationHandler implements InvocationHandler {
Activity ac;
Method method;
public ListenerInvocationHandler(Activity ac,Method method){
this.ac = ac;
this.method = method;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return this.method.invoke(ac,args);
}
}