代理(Proxy)
Proxy代理类的理解:
在系统程序设计中,有时需要面对无法确定接口,却需要构造对象的情况。通过代理类,能够在不额外创建Java文件的情况下构造对象及调用该对象方法。(系统程序设计用得较多,应用程序设计遇到的情况比较少)
代理类可以在运行时创建全新的类,这样的代理类能够实现指定的接口,尤其是,它具有下列方法:
- 指定接口所需要的全部方法。
- Object类中的全部方法,例如:toString ,equals等等。
但是不能在运行时定义这些方法的新代码,而是要提供一个调用处理器(invocationhandler),调用处理器实现了InvocationHandler接口的类对象。
调用处理器
InvocationHandler 这个接口只有一个方法。这个方法定义了代理对象调用方法时希望执行的动作。即方法具体要做什么…
Object invoke(Object proxy, Method method, Object[] args)
- 第一个参数为代理类本身
- 第二个参数为method 对象
- 第三个参数为其原始的调用参数
在这个调用处理器的方法中,必须给出处理调用的方式,
创建代理对象
想要创建一个代理对象,需要使用Proxy类的newProxyInstance 方法。该方法构造一个实现指定接口的代理类的实例,所有方法都将调用给调用处理器(InvocationHandler)的invoke方法。
static Object newProxyInstance(ClassLoader loader Class[] interfaces, InvocationHandler handler)
- 第一个参数为 类加载器,使用null表示使用默认的类加载器(这个另行查阅)
- 第二个参数为一个Class对象数组,每个元素都是需要实现的接口
- 第三个参数为调用处理器
例子:见代码
其他:
- 代理类是在程序运行过程中创建的。然而,一旦被创建,就变成了常规类,与虚拟机中的其他任何类没有区别。
- 所有代理类都扩展于Proxy类,一个代理类只有一个实例域——调用处理器,它定义在Proxy的超类中。
- 所有的代理类都覆盖了Object类中的方法toString,equals,hashCode.如同所有的代理方法一样,这些方法仅仅调用了调用处理器的Invoke。其他方法没有被重新定义。
- 对于特定的类加载器和预设的一组接口来说,只能有一个代理类。可以通过 getProxyClass()方法获得这个类
Class proxyClass = Proxy.getProxyClass(null, interface);
第一个参数为ClassLoader 第二个参数为 接口对象数组- 可以通过isProxyClass(Class c) 来判断一个类是否为代理类。
注解(Annotation)
注解是那些插入到源代码中使用其他工具可以对其进行处理的标签。
为了能够受益于注解。需要选择一个处理工具,然后向处理工具可以理解的代码中插入注解,之后运用该处理工具处理代码。
任何一个注解自身不会做任何事情,他需要工具支持才会有用。一般为代理类- 在Java中,注解是当作一个修饰符来使用的,它被置于被注解项之前,中间没有分号。每个注解的名称前面都加上了@ 符号。类似于javadoc的注释,但是注解是代码的一部分。
- 所有注解接口都隐式的扩展自 java.lang.annotation.Annotation接口,这个接口是一个常规接口,不是注解接口。注解接口无法扩展
- 一个项可以有多个注解,只要它们是不同的类型即可。
自定义注解
/**
* 标记网络请求基本设置, 请求类型
* Created by wangyy on 2016/5/23.
*/
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface IRequest {
enum METHOD {POST, GET, PUT, DELETE}
METHOD method() default METHOD.POST; // 默认值为动态计算的,而不是和注解存储在一起的
String url();
}
@IRequest(url = "/user/loginMobile")
VolleyRequest<UserInfo> login(@IBody Map<String, Object> params, @IHeader("aaa") Map<String, Object> params); // 登录
有两种特殊的快捷方式可以简化注解:
- 如果没有指定元素,要么是因为注解中没有任何元素,要么是因为所有元素都使用默认值,那么久可以不用圆括号。如@IBody。又称为标记注解。
- 单值注解。如果一个元素具有特殊的名字value,并且没有指定其他元素,就可以忽略掉这个元素名以及等号。如 @IHeader(“aaa”)
注解接口中的元素声明实际上是方法声明。一个注解接口的方法不能有任何参数和throws语句,并且他们也不能是泛型的。注解元素的类型:
- 基本类型
- String
- Class
- enum 类型
- 注解类型 // 可以声明一个注解,有多个更简单的注解组成
- 由前面所述类型组成的数组
Public @interface BugReport{
enum Status{UNCONFIRMED, CONFIRMED, FIXED, NOTABUG}
boolean showstopper() default false;
String assignedTo() default “”;
Class<?> testCase() default void.class;
Status status() default Status.FIXED;
Reference ref default @Reference();// an annotation type
String[] reportedBy();
}
标准注解
用于编译的注解:
- @Override 告诉编译器这个方法要覆盖一个超类方法,防止程序员覆盖出错。
- @Deprecated 这个标识方法或类(接口等类型)过期,警告用户不建议使用。
- @SafeVarargs JDK7新增,避免可变参数在使用泛型化时候警告”执行时期无法具体确认参数类型“,当然,也可以用@SuppressWarnings来避免检查,显然后者的抑制的范围更大。
- @SuppressWarnings(value={“unchecked”}) 抑制编译警告,应用于类型、构造器、方法、域、参数以及局部变量。
- @Generated
用于管理资源的注解:
- @PostConstruct, @PreDestroy
- @Resource
元注解
@Target
可以应用于一个注解,以限制该注解可以应用到哪些项上。如@Target({ElementType.METHOD})
public enum ElementType {
/**
* Class, interface or enum declaration. 类及接口包括enum,注解类型
*/
TYPE,
/**
* Field declaration. 成员域(包括enum常量)
*/
FIELD,
/**
* Method declaration. 方法
*/
METHOD,
/**
* Parameter declaration. 方法或构造器参数
*/
PARAMETER,
/**
* Constructor declaration. 构造器
*/
CONSTRUCTOR,
/**
* Local variable declaration. 局部变量
*/
LOCAL_VARIABLE,
/**
* Annotation type declaration. 注解类型声明
*/
ANNOTATION_TYPE,
/**
* Package declaration. 包
*/
PACKAGE
}
自己本身也是一个注解,注解可以用于自己
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE) // 应用于注解类型声明
public @interface Target {
ElementType[] value();
}
@Retention
用于指定一条注解应该保留多长时间。 如@Retention(RetentionPolicy.RUNTIME)
public enum RetentionPolicy {
/**
*不包括在类文件中的注解
*/
SOURCE,
/**
* 包括在类文件中的注解,但是虚拟机不需要将他们载入
*/
CLASS,
/**
* 包括在类文件中的注解,并由虚拟机载入,通过反射API可获得它们
*/
RUNTIME
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
@Decumented
为像Javadoc这样的归档工具提供了一些提示
@Inherited
只能应用于对类的注解。指明当这个注解应用于一个类的时候,能够自动被它的子类继承