开发过程中使用注解将增加程序的灵活性和扩展性,注解可以修饰接口、类、方法、属性等。
1.反射获取注解
能够通过反射获取类上的注解,主要依赖于核心类AccessibleObject(如下图,Java10的DOC),其实现了AnnotatedElement类。另外其子类包含Field、Executable(Method和Constructor)。
还可以通过该类可以设置属性的可见性,如getFields()获取所有属性,其中只包含父类的public属性,通过setAccessible(true),即可获取私有属性。

(1)获取注解主要方法:
获取所有注解(包含继承的):public Annotation[] getAnnotations()
获取指定注解(包含继承的):public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
获取所有注解(不包含继承的):public Annotation[] getDeclaredAnnotations()
获取指定注解(不包含继承的):public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
(2)什么类型的注解可以通过反射获取到?
① 只有被Retention(RUNTIME)修饰的注解接口才可以通过反射在运行时获取,其中RUNTIME为 RetentionPolicy
② Retention注解标识对应注解维持到什么阶段,具体由RetentionPolicy决定
③ 枚举类RetentionPolicy为注解维持策略,取值SOURCE(编译期)、CLASS(维持到class文件,默认值)、RUNTIME(维持到运行时)
如注解SuppressWarnings维持到SOURCE,无法通过反射获取到该注解
@Target({TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,MODULE})
@Retention(SOURCE)
public @interface SuppressWarnings如功能接口注解FunctionalInterface,维持到RUNTIME,即可通过反射获取到该注解。
@Documented
@Retention(RUNTIME)
@Target(TYPE)
public @interface FunctionalInterface2.自定义注解
自定义注解:@interface.
下边是自定义注解,声明title,url(带默认值),seq(带默认值),并将注解修饰到方法上,如下:
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
public String title();
public String url() default "www.baidu.com";
public int seq() default 0;
}
class Message{
@MyAnnotation(title = "message", seq = 1)
public void send(String msg, int seq){
System.out.println("消息发送:"+msg);
System.out.println("消息序号:"+seq);
}
}测试:获取Method对象和对应的所有注解,并通过判断是否存在自定义的注解,进行调用对应方法,如下:
public class AnnotationTest {
public static void main(String[] args) throws Exception{
Method method = Message.class.getDeclaredMethod("send", String.class, int.class);
Annotation[] anno = method.getDeclaredAnnotations();
for(Annotation an : anno){
if(an instanceof MyAnnotation){
MyAnnotation an1 = (MyAnnotation)an;
String msg =an1.title() + " " + an1.url();
method.invoke(Message.class.getDeclaredConstructor().newInstance(), msg, an1.seq());
}
}
}
}输出:
消息发送:message www.baidu.com
消息序号:13.工厂设计模式与Annotation
注解可以加强代码的复用,可以控制代码具体实现,下边举例综合工厂设计模式、代理和Annotation。
/**
* 指定运行的注解类
*/
@Retention(RetentionPolicy.RUNTIME)
@interface ToClass{
public Class<?> clazz();
}
/**
* 工厂类
*/
class InstanceFactory{
private InstanceFactory(){}
public static <T> T getInstance(Class<T> clazz){
try{
//代理+反射实例化
return (T)new MyProxy().bind(clazz.getDeclaredConstructor().newInstance(), clazz);
}catch (Exception e){
return null;
}
}
}
/**
* 动态代理类
*/
class MyProxy implements InvocationHandler{
private Object target;
public <T> T bind(Object target, Class<T> clazz){
this.target = target;
return (T)Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable{
try {
if(this.connect()){
return method.invoke(target, args);
}
}finally {
this.close();
}
return null;
}
private boolean connect(){
System.out.println("创建连接");
return true;
}
private void close(){
System.out.println("关闭连接");
}
}注解使用,通过该注解控制具体属性值,该例中设置clazz=MsgImpl.class,通过工厂生成代理后的对象,并赋给MsgService实例。
@ToClass(clazz = MsgImpl.class)
class MsgService{
private Msg msg;
public MsgService(){
ToClass clazzAnno = MsgService.class.getDeclaredAnnotation(ToClass.class);
msg = (Msg)InstanceFactory.getInstance(clazzAnno.clazz());
}
public void send(String text){
msg.send(text);
}
public String recv(String text){
return msg.recv(text);
}
}
interface Msg{
void send(String msg);
String recv(String msg);
}
class MsgImpl implements Msg{
public void send(String msg) {
System.out.println("消息发送:"+msg);
}
public String recv(String msg) {
System.out.println("消息接收:"+msg);
return msg;
}
}测试:
public static void main(String[] args){
MsgService msgService = new MsgService();
msgService.send("hello");
msgService.recv("hello world");
}输出:
创建连接
消息发送:hello
关闭连接
创建连接
消息接收:hello world
关闭连接当把MsgService改为如下时,底层将执行NetMsgImpl对用的方法。
@ToClass(clazz = NetMsgImpl.class)
class MsgService{
.....
}总结
自定义注解可以控制代码具体实现,增加代码的复用。另外,将反射与注解结合,可以实现具备特定功能的框架,如Spring。
















