zoukankan      html  css  js  c++  java
  • Java 自定义注解

    部分资料来源:

    1. 深入理解Java:注解(Annotation)自定义注解入门
    2. Java自定义注解和运行时靠反射获取注解
    3. Java自定义注解的定义与使用

    Java 自定义注解

    元注解

    Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。
    注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。
    元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
        1.@Target,
        2.@Retention,
        3.@Documented,
        4.@Inherited
    这些类型和它们所支持的类在java.lang.annotation包中可以找到。

    @Target:###

    @Target说明了Annotation所修饰的对象范围

    Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

    作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

    取值(ElementType)有:
        1.CONSTRUCTOR:用于描述构造器
        2.FIELD:用于描述域
        3.LOCAL_VARIABLE:用于描述局部变量
        4.METHOD:用于描述方法
        5.PACKAGE:用于描述包
        6.PARAMETER:用于描述参数
        7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

    @Target(ElementType.TYPE)
    public @interface Table {
        /**
         * 数据表名称注解,默认值为类名称
         * @return
         */
        public String tableName() default "className";
    }
    
    @Target(ElementType.FIELD)
    public @interface NoDBColumn {
    
    }
    

    注解Table 可以用于注解类、接口(包括注解类型) 或enum声明,而注解NoDBColumn仅可用于注解类的成员变量。

    @Retention:###

    @Retention定义了该Annotation被保留的时间长短

    某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

    作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

    取值(RetentionPoicy)有:
        1.SOURCE:在源文件中有效(即源文件保留)
        2.CLASS:在class文件中有效(即class保留)
        3.RUNTIME:在运行时有效(即运行时保留)

    Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。具体实例如下:

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Column {
        public String name() default "fieldName";
        public String setFuncName() default "setField";
        public String getFuncName() default "getField"; 
        public boolean defaultDBValue() default false;
    }
    

    Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理

    @Documented:###

    @Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Column {
        public String name() default "fieldName";
        public String setFuncName() default "setField";
        public String getFuncName() default "getField"; 
        public boolean defaultDBValue() default false;
    }
    

    @Inherited:

    @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了 @Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

    注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

    当 @Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个 @Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

    @Inherited
    public @interface Greeting {
        public enum FontColor{ BULE,RED,GREEN};
        String name();
        FontColor fontColor() default FontColor.GREEN;
    }
    

    自定义注解:##

    使用 @interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
    定义注解格式:
    public @interface 注解名 {定义体}
    注解参数的可支持数据类型:

        1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
        2.String类型
        3.Class类型
        4.enum类型
        5.Annotation类型
        6.以上所有类型的数组

    Annotation类型里面的参数该怎么设定:
    第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;
    第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations 等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
    第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:下面的例子FruitName注解就只有一个参数成员。

    简单的自定义注解和使用注解实例:

    实例1

    定义水果名称注解:

    package annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 水果名称注解
     * @author peida
     *
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface FruitName {
        String value() default "";
    }
    

    定义水果颜色注解:

    package annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 水果颜色注解
     * @author peida
     *
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface FruitColor {
        /**
         * 颜色枚举
         * @author peida
         *
         */
        public enum Color{ BULE,RED,GREEN};
        
        /**
         * 颜色属性
         * @return
         */
        Color fruitColor() default Color.GREEN;
    
    }
    

    使用注解的类:

    package annotation;
    
    import annotation.FruitColor.Color;
    
    public class Apple {
        
        @FruitName("Apple")
        private String appleName;
        
        @FruitColor(fruitColor=Color.RED)
        private String appleColor;
        
        
        
        
        public void setAppleColor(String appleColor) {
            this.appleColor = appleColor;
        }
        public String getAppleColor() {
            return appleColor;
        }
        
        
        public void setAppleName(String appleName) {
            this.appleName = appleName;
        }
        public String getAppleName() {
            return appleName;
        }
        
        public void displayName(){
            System.out.println("水果的名字是:苹果");
        }
    }
    

    注解元素的默认值:

    注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。例如:

    package annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 水果供应者注解
     * @author peida
     *
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface FruitProvider {
        /**
         * 供应商编号
         * @return
         */
        public int id() default -1;
        
        /**
         * 供应商名称
         * @return
         */
        public String name() default "";
        
        /**
         * 供应商地址
         * @return
         */
        public String address() default "";
    }
    

    定义了注解,并在需要的时候给相关类,类属性加上注解信息,如果没有响应的注解信息处理流程,注解可以说是没有实用价值。如何让注解真真的发挥作用,主要就在于注解处理方法。

    实例2

    定义注解:

    @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到  
    @Target({ElementType.FIELD,ElementType.METHOD})//定义注解的作用目标**作用范围字段、枚举的常量/方法  
    @Documented//说明该注解将被包含在javadoc中  
    public @interface FieldMeta {  
      
        /** 
         * 是否为序列号 
         * @return 
         */  
        boolean id() default false;  
        /** 
         * 字段名称 
         * @return 
         */  
        String name() default "";  
        /** 
         * 是否可编辑 
         * @return 
         */  
        boolean editable() default true;  
        /** 
         * 是否在列表中显示 
         * @return 
         */  
        boolean summary() default true;  
        /** 
         * 字段描述 
         * @return 
         */  
        String description() default "";  
        /** 
         * 排序字段 
         * @return 
         */  
        int order() default 0;  
    }  
    

    定义类:

    public class Anno {  
      
        @FieldMeta(id=true,name="序列号",order=1)  
        private int id;  
        @FieldMeta(name="姓名",order=3)  
        private String name;  
        @FieldMeta(name="年龄",order=2)  
        private int age;  
          
        @FieldMeta(description="描述",order=4)  
        public String desc(){  
            return "java反射获取annotation的测试";  
        }  
          
        public int getId() {  
            return id;  
        }  
        public void setId(int id) {  
            this.id = id;  
        }  
        public String getName() {  
            return name;  
        }  
        public void setName(String name) {  
            this.name = name;  
        }  
        public int getAge() {  
            return age;  
        }  
        public void setAge(int age) {  
            this.age = age;  
        }  
          
    } 
    

    实例3

    定义注解1:

    package com.annotation.test;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface FruitColor {
    
        enum Color{RED,YELLOW,WHITE}
        
        Color fruitColor() default Color.RED;
        
    }
    

    定义注解2:

    package com.annotation.test;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface FruitName {
    
        String value() default "";
        
    }
    

    定义注解3:

    package com.annotation.test;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface FruitProvider {
    
        int id() default 0;
        
        String user() default "";
        
        String address() default "";
        
    }
    

    定义实体类:

    package com.annotation.test;
    
    import com.annotation.test.FruitColor.Color;
    
    public class Apple {
    
        @FruitName(value="FuShi Apple")
        private String fruitName;
        
        @FruitColor(fruitColor=Color.RED)
        private String fruitColor;
        
        @FruitProvider(id=1,user="Tom",address="China")
        private FruitProvider provider;
    }
    

    定义测试类:

    package com.annotation.test;
    
    import java.lang.reflect.Field;
    
    public class Test {
    
        
        public static void getFruitInfo(String clas){
            try {
                Class<?> cls = Class.forName(clas);
                Field[] fields = cls.getDeclaredFields();
                
                for (Field field : fields) {
                    if(field.isAnnotationPresent(FruitName.class)==true){
                        FruitName name = field.getAnnotation(FruitName.class);
                        System.out.println("Fruit Name:"+name.value());
                    }
                    if(field.isAnnotationPresent(FruitColor.class)){
                        FruitColor color = field.getAnnotation(FruitColor.class);
                        System.out.println("Fruit Color:"+color.fruitColor());
                    }
                    if(field.isAnnotationPresent(FruitProvider.class)){
                        FruitProvider Provider = field.getAnnotation(FruitProvider.class);
                        System.out.println("Fruit FruitProvider: ProviderID:"+Provider.id()+" Provider:"+Provider.user() +" ProviderAddress:"+Provider.address());
                    }
                }
                
                
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        
        public static void main(String[] args) {
            getFruitInfo("com.annotation.test.Apple");
        }
        
    }
    

    输出结果:

    Fruit Name:FuShi Apple
    Fruit Color:RED
    Fruit FruitProvider: ProviderID:1 Provider:Tom ProviderAddress:China
  • 相关阅读:
    SCI论文写作中一些常见的用词不当
    英语医学论文SCI写作/医学翻译中的常见错误
    SCI写作的20例常见错误集锦
    sci写作结构总结二——整体结构逻辑
    关于 mysql 优化 -------复合索引的一些见解
    win10系统没有Hyper-v解决办法
    win10 docker 安装redis activemq,mysql等。
    win10环境下的docker 设置镜像
    win10 安装docker
    jquery瀑布流
  • 原文地址:https://www.cnblogs.com/cuiyf/p/7111674.html
Copyright © 2011-2022 走看看