反射与Annotataion(阿里云开发者社区学习笔记)

反射取得Annotation信息

从JDK1.5之后Java开发提供了Annotation技术支持,这种技术为项目的编写带来了新的模型,而后经过十多年的发展,Annotation技术已经得到了广泛应用,并且在所有的项目中都会存在

在进行类或方法进行的时候都可以使用Annotation进行声明,于是如果要想获取这些Annotation的信息,那么就可以直接通过反射来完成。在java.lang.reflect里面有一个AccessibleObject类在本类中提供有获取Annotation类的方法

‒ 获取全部Annotation:public Annotation[] getAnnotations​()
‒ 获取指定Annotation:public T getAnnotation​(Class annotationClass)

范例:定义一个接口,并且在接口上使用Annotation

import java.io.Serializable;
import java.lang.annotation.Annotation;

@FunctionalInterface
@Deprecated(since="1.0")
interface IMessage{
    public void send(String msg);
}

@SuppressWarnings("serial")  // 无法在程序执行的时候获取
class MessageImpl implements IMessage, Serializable {
    @Override // 无法在程序执行的时候获取
    public void send(String msg){
        System.out.println("[消息发送]+msg");
    }
}

public class JavaAPIDemo{
    public static void main(String args[])throws Exception{
        { // 获取接口上的Annotation信息
            Annotation annotations [] = IMessage.class.getAnnotations(); // 获取接口上的全部的Annotation
            for(Annotation temp:annotations){
                System.out.println(temp);
            }
        }
System.out.println("-----------------------------");
{ //获取MessageImpl子类上的Annotation
Annotation annotations [] =  MessageImpl.class.getAnnotations(); //获取类上全部的Annotation
for(Annotation temp:annotations){
System.out.println(temp);
}
}
System.out.println("-----------------------------");
{ //获取MessageImpl.toString()方法上的Annotation
Method methods = MessageImpl.class.getDeclaredMethod("send",String.class);
Annotation annotations [] =  methods.getAnnotations(); //获取类上全部的Annotation
for(Annotation temp:annotations){
System.out.println(temp);
}
}
    }
}

不同的Annotation有它的存在范围,下面对比两个Annotation
@FunctionalInterface(运行时)

@Documented
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

@SuppressWarnings(“serial”) (源代码)

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

现在发现"@FunctionalInterface"是在运行时生效的Annotation,所以当程序执行的时候可以获取此Annotation,而"@SuppressWarnings(“serial”)"是在源代码编写的时候有效(.java)。而在RetentionPolicy枚举类中还有一个class的定义,指的是在类定义的时候生效(.class)

不同的Annotation策略决定了能否被Annotation所读取

自定义Annotation

现在已经清楚了Annotation的获取,以及Anotation运行的策略,但是最为关键性的因素是如何可以实现自定义的Annotation呢?为此在Java里面提供了新的语法,使用"@interface"来定义Annotation

范例:自定义Annotation

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

@Retention(RetentionPolicy.RUNTIME) // 定义Annotation的运行策略
@interface DefaultAnnotation{
    // 自定义的Annotation
    public String title(); // 获取数据
    public String url() default "www.baidu.com" ;// 获取数据,默认值
}
class Message06{
    @DefaultAnnotation(title="BAIDU")
    public void send(String msg){
        System.out.println("消息发送"+msg);
    }
}
public class JavaAPIDemo39 {
    public static void main(String args[])throws Exception{
        Method method =Message06.class.getMethod("send",String.class);//获取指定方法
        DefaultAnnotation anno = method.getAnnotation(DefaultAnnotation.class);
        System.out.println(anno.title()); // 直接调用Annotation中的方法
        System.out.println(anno.url());
        String msg = anno.title() + "("+anno.url()+")";//消息内容
        method.invoke(Message06.class.getDeclaredConstructor().newInstance(),msg);
    }
}

使用Annotation之后的最大特点是可以结合反射机制实现程序的处理

工厂设计模式与Annotation

现在已经清楚了Annotation的整体作用,但是Annotation到底在开发之中能做哪些事情呢?为了帮助大家进一步理解Annotation的处理目的下面将结合工厂设计模式来应用Annotation操作

范例:与Annotation结合


import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JavaAPIDemo40 {
    public static void main(String args[]){
        MessageService messageService =  new MessageService();
        messageService.send("www.mldn.cn");
    }
}
@Retention(RetentionPolicy.RUNTIME)
@interface  UseMessage {
    public Class<?> clazz();
}
@UseMessage(clazz = NetMessageImpl.class) // 利用Annotation实现了类的使用
class MessageService{
    // 对主方法调用进行包装,主方法不需要知道那么多,只需要知道对象产生
    private IMessage07 message;
    public MessageService(){
        UseMessage use =MessageService.class.getAnnotation(UseMessage.class);
        this.message = (IMessage07)Factory.getInstance(use.clazz()); // 直接通过Annotation获取
    }
    public  void send(String msg){
        this.message.send(msg);
    }
}
class Factory{
    private Factory(){}
    public  static <T> T getInstance(Class<T> clazz){  // 直接返回一个实例化对象
        try{
            return (T)new MessageProxy().bind(clazz.getDeclaredConstructor().newInstance());
        }catch(Exception e){
            e.printStackTrace();
            return null;
        }
    }
}
interface IMessage07{
    public void send(String msg);
}
class MessageImpl implements IMessage07{
    @Override
    public void send(String msg){
        System.out.println("[消息发送]"+msg);
    }
}
class NetMessageImpl implements IMessage07{
public void send(String msg){
System.out.println("[网络消息发送]"+msg);
}
}
class MessageProxy implements InvocationHandler {
    public Object target;
    public Object bind(Object target){
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }
    public Object invoke(Object proxy, Method method, Object[] args ) throws Throwable{
        try {
            if(this.connect()){
                return method.invoke(this.target,args);
            }else{
                throw new Exception("[ERROR]消息无法进行发送");
            }
        }
        finally{
            this.close();
        }
    }
    public boolean connect(){
        System.out.println("[代理操作]进行消息发送通道的连接");
        return true;
    }
    public void close(){
        System.out.println("[代理操作]关闭连接通道");
    }
}

由于Annotation的存在,所以对于面向接口的配置处理将可以直接利用Annotation的属性完成控制,从而使得整体代码变得简洁

学习资料

阿里云开发者社区

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值