zoukankan      html  css  js  c++  java
  • Java反射(四)反射与注解

     开发过程中使用注解将增加程序的灵活性和扩展性,注解可以修饰接口、类、方法、属性等。

    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 FunctionalInterface

    2.自定义注解

    自定义注解:@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
    消息序号:1

    3.工厂设计模式与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。 

    
    
  • 相关阅读:
    Git第一次新建项目添加ssh key
    第一次将本地项目同步到git服务器
    python实现差分隐私Laplace机制
    利用皮尔逊相关系数找出与目标最相关的特征(Python实现)
    corrcoef函数python_用Numpy计算Python中的Pearson相关系数
    Python Numpy库 numpy.corrcoef()函数讲解
    皮尔森相关系数(Pearson correlation coefficient)
    Python三种方法计算皮尔逊相关系数(Pearson correlation coefficient)
    特征选择 (feature_selection)
    基于模型的特征选择详解
  • 原文地址:https://www.cnblogs.com/shuimuzhushui/p/12676796.html
Copyright © 2011-2022 走看看