zoukankan      html  css  js  c++  java
  • java注解(Annotation)解析

    注解(Annotation)在java中应用非常广泛。它既能帮助我们在编码中减少错误,(比如最常见的Override注解),还可以帮助我们减少各种xml文件的配置,比如定义AOP切面用@AspectJ模式代替Schema模式,特别是最近接触了一点Spring MVC,每次编写Controller的时候用@RequestMapping(),@RequestParam,@ResponseBody等等。

    我们所用的java中自带的注解都是定义好了的,直接拿来用,它就能发挥作用。当然了,自己也可以定义注解。

    注解定义:

    public @interface 注解名 {
        
        //
    } 

    可以给注解中可以定义“属性”,暂且理解为属性吧,定义如下:

    public @interface MyAnnotation {
        
        String hello(); // 定义了一个属性名hello
    
        String world() default "world";// 定义了一个属性名world,默认值为“world”,注意类型匹配
    
        int number();// 定义了一个属性名为number
    
        String[] value(); // 定义了一个属性为value的数组
    
    }

    后面必须有括号,修饰符只能为public或abstract,不过一般都是默认不写的。

    当我们定义一个注解时,它暗自的继承了Annotation这个借口。如果手动定义了一个Interface 并继承了java.lang.annotation.Annotation,并不意味着定义了一个注解。注解只能通过@Interface方式定义。Annotation是一个接口而不是一个注解。

    使用方式:

    1.当我们对一个注解定义了多个属性后,在使用该注解时,除了定义了默认值的属性,其他属性都要赋值。当然,也可以显式的对含有默认值的属性赋值。

    例如:

    public class MyAnnotationTest{
        
        private String name;
        @MyAnnotation(hello = "", number = 0, value = { "aa" },world="world1")
        public static void main(String[] args) {
            MyAnnotationTest test = new MyAnnotationTest();
            test.method();
        }
        @MyAnnotation(hello = "hello", number = 0, value = {"a"},world="aa")
        public void method(){
            System.out.println("method");
        }
    }

    2.当一个注解只含有一个属性且属性名为value时,我们可以简化使用方式。

    比如定义一个注解:
    public @interface SingleAnnotation {
        String[] value();
    }

    在使用在注解时可以简化:

        @SingleAnnotation("value")
        public void singleAnnotationMethod(){
            
        }    

     注解基本的定义和使用差不多就这些了。接下来看看定义的注解为什么会生效。

    @Retention注解

     为了更好的使用注解,java内置的这个注解也是需要了解的。

    java.lang.annotation.Retention可以告诉编译器怎样去对待和处理我们自定义的注解。默认情况下会将Annotation的信息留在class文件中,但不会被JVM读取。

    在使用Retention注解时,需要提供java.lang.annotation.RetentionPolicy的枚举值。编译器会根据设置不同的值来决定如何处理定义的注解。

    RetentionPolicy定义如下:

    public enum RetentionPolicy {
       
        SOURCE, //编译程序丢弃该注解,表示他不会存在于class文件中
    
        CLASS, //编译程序将Annotation存在class文件中(缺省)
    
        RUNTIME //编译程序将Annotation存在class文件中,可由JVM读取
    }

     比如@SuppressWarnings注解,它所对应的@Retention(RetentionPolicy.SOURCE)是这样设置的,因为它的作用是告知编译程序来压制警告,没必要将这个信息存在于class文件中。

    RetentionPolicy.RUNTIME:搭配反射机制,可以让注解被JVM读出。

    一个注解信息如何被JVM读出

      1.将该注解加上 @Retention(value = RetentionPolicy.RUNTIME)。

      1.获得一个类的class对象

      2.获得这个类中被该注解修饰的方法或属性。 AccessibleObject的isAnnotationPresent(Class<? extends Annotation> annotationClass)方法可以判断一个注解是否出现,由于Field和Method类继承了AccessibleObject,所以可以判断出一个类的方法或属性是否有该注解。又因为Method实现了AnnotatedElement ,所以method可以得到它对应的注解的Annotation对象,进而可以获取注解的相关信息。

    下面给出例子:

    首先给MyAnnotation注解 加上 @Retention(value = RetentionPolicy.RUNTIME)。

    public class MyAnnotationTest{
        
        
        public static void main(String[] args)throws Exception{
            MyAnnotationTest test = new MyAnnotationTest();
            
            Class<?> clazz = test.getClass();
            Method[] methods = clazz.getMethods();
            
            for(Method m : methods){
                //该方法是否出现MyAnnotation注解,出现为true,否则为false
                if(m.isAnnotationPresent(MyAnnotation.class)){
                    
                    MyAnnotation annotation = m.getAnnotation(MyAnnotation.class);
                    String hello = annotation.hello();
                    int number = annotation.number();
                    String[] values = annotation.value();
                    String world = annotation.world();
                    
                    m.invoke(test,new Object[]{});
                    
                    System.out.println("annotation.hello():" + hello);
                    System.out.println("annotation.number():" + number);
                    System.out.println("annotation.value():" + values[0]);
                    System.out.println("annotation.world():" + world);
                    
                }
            }
        }
        
        @MyAnnotation(hello = "hello", number = 100, value = {"a"},world="aa")
        public void method(){
            System.out.println("method");
        }
        public void method2(){
            System.out.println("method2");
        }
        
    }

    console 结果:

    结果一目了然,可以让该方法执行,可以拿到该注解的所有赋值情况。

    如果 MyAnnotation的Retention注解为 @Retention(value = RetentionPolicy.CLASS) 或@Retention(value = RetentionPolicy.SOURCE),那么method方法也不会执行,更不会获取到MyAnnotation的先关信息了。

    @Target注解

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        ElementType[] value();
    }

    它也是用来注解我们定义的注解。value为ElementType类型的枚举值。

    ElementType定义:

    public enum ElementType {
        /** Class, interface (including annotation type), or enum declaration */
        TYPE,
    
        /** Field declaration (includes enum constants) */
        FIELD,
    
        /** Method declaration */
        METHOD,
    
        /** Parameter declaration */
        PARAMETER,
    
        /** Constructor declaration */
        CONSTRUCTOR,
    
        /** Local variable declaration */
        LOCAL_VARIABLE,
    
        /** Annotation type declaration */
        ANNOTATION_TYPE,
    
        /** Package declaration */
        PACKAGE
    }

    好吧,不用解释了,看注释都知道每一个值是什么意思了。

    如果一个注解被@Target直接,那么该注解所修饰的类型将受到限制,如果修饰的类型不匹配编译将会报错。

    表示MyAnnotation注解只能修饰方法,可根据ElementType 的值以此类推。

    @Documented

    它表示被修饰的注解将会生成到javadoc帮助文档中。

    @Inherited:允许子类继承父类的注解。缺省情况下子类并不会继承父类中的Annotation.

    就算java的原生注解,一般也是被这几种注解中的一种或多种修饰,进而达到其功能。

    总结:个其实java注解的原理还是反射。在运行时,因为有了注解,利用反射机制在运行时才会找到注解对应的方法,找到注解对应的值。值拿到了,方法也找到了,想干什么就干什么了,该干什么这一般应该是底层或框架做的事情。但我想应该就是这么回事吧!

  • 相关阅读:
    吴裕雄--天生自然Django框架开发笔记--Django 路由
    吴裕雄--天生自然Django框架开发笔记--Django 视图
    吴裕雄--天生自然Django框架开发笔记--Django 表单
    吴裕雄--天生自然Django框架开发笔记--Django 模型
    Redis07——Redis到底能用在什么地方(下)
    Redis06——Redis到底能用在什么地方(上)
    Redis05——Redis Cluster 如何实现分布式集群
    Redis04——五分钟明白Redis的哨兵模式
    Redis03——Redis是如何删除你的数据的
    Redis02——Redis内存数据如何保存到磁盘
  • 原文地址:https://www.cnblogs.com/xxez-d/p/4769278.html
Copyright © 2011-2022 走看看