java 注解详解+示例

2022-06-27 13:17:57

注解介绍

  • 1.5开始引入
  • 注解可以理解为一种描述数据的数据,或者可以称为一种描述元数据的方法。
  • java提供的默认注解:@Override,@Deprecated。
  • 注解仅仅是元数据,和业务逻辑无关
  • 定义方法在 java.lang.annotation包中

元注解

java提供4中元注解来定义我们的注解
1. @Target,
2. @Retention,
3. @Documented,
4. @Inherited

1. @Target,

@Target说明了Annotation所修饰的对象范围,即用于描述注解的使用范围
1. CONSTRUCTOR:用于描述构造器
2. FIELD:用于描述域
3. LOCAL_VARIABLE:用于描述局部变量
4. METHOD:用于描述方法
5. PACKAGE:用于描述包
6. PARAMETER:用于描述参数
7. TYPE:用于描述类、接口(包括注解类型) 或enum声明
8. ANNOTATION_TYPE:适用于annotation类型,声明注解类型
9. TYPE_PARAMETER:1.8版本
10. TYPE_USE: 1.8版本

TYPE_PARAMETER和TYPE_USE扩展了泛型使用场景,包括泛型、超类和接口实现、甚至是方法的Exception声明。

2. @Retention

  1. SOURCE:在源文件中有效(即源文件保留),在编译阶段丢弃。注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。比如:@Override
    2.CLASS:在class文件中有效(即class保留)。在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
    3.RUNTIME:在运行时有效(即运行时保留)。 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息比。如:@Deprecated。比如Srping中的@Autowired,@ResponseBody等都属于这一类。

表示需要在什么级别保存该注释信息,用于描述注解的生命周期

3. @Inherited

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

使用此注解声明出来的自定义注解,在使用此自定义注解时,如果注解在类上面时,子类会自动继承此注解,否则的话,子类不会继承此注解。这里一定要记住,使用Inherited声明出来的注解,只有在类上使用时才会有效,对方法,属性等其他无效。

4. @Documented

一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。

表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的。

示例:
在某个方法上增加了有Documented注解的元注解,则javadoc命令生成xxx.html文件中。可以看到该注解。

注解元素

注解类中定义的元素称为注解元素,注解元素可用的类型如下:
- 所有基本数据类型(int,float,boolean,byte,double,char,long,short)
- String类型
- Class类型
- enum类型
- Annotation类型
- 以上所有类型的数组

实际使用注意问题

1. 使用注解不使用名字时,赋值规则,

  • 如果注解只有一个属性,那么肯定是赋值给该属性。

  • 如果注解有多个属性,而且前提是这多个属性都有默认值,那么你不写注解名赋值,会赋值给名字为“value”这属性。

  • 如果注解有多个属性,其中有没有设置默认值的属性,那么当你不写属性名进行赋值的时候,是会报错的。

2. 若注解中定义了多个注解元素,除非注解元素使用的default。否则在使用该注解时,都需要赋值。

示例

1. 变量上的注解

1.1 注解定义@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interfaceFieldAnno {public StringfileName()default "defaultFileName";publicintvalue();

}1.2 使用publicclassMyAnno {@FieldAnno(111)private String myStr;
    ...
}1.3 调用/**
     * 根据字段名
     */publicstaticvoidgetFieldAnno() {try {
            Field myfiel = MyAnno.class.getDeclaredField("myStr");//            myfiel.setAccessible(true);
            FieldAnno fieldAnno = myfiel.getAnnotation(FieldAnno.class);if (fieldAnno !=null) {
                System.out.println("----getFieldAnno----");
                System.out.println(fieldAnno.fileName());
                System.out.println(fieldAnno.value());
            }
        }catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }/**
     * 搜索所有字段
     */publicstaticvoidgetFieldAnno2() {

        Field[] fields = MyAnno.class.getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(FieldAnno.class)) {
                FieldAnno fieldAnno = field.getAnnotation(FieldAnno.class);
                System.out.println("----getFieldAnno2----");
                System.out.println(fieldAnno.fileName());
                System.out.println(fieldAnno.value());
            }
        }


    }

2. 一般方法上的注解

2.1 定义@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interfaceMethodAnno {
    String methodNamett();
}2.2 使用@MethodAnno(methodNamett ="mycustomerMethod")privatestaticvoidmyMethod(){

    }2.3 调用/**
     * 根据方法名获取
     */publicstaticvoidgetMethodAnno() {try {

            Method myMethod = MyAnno.class.getDeclaredMethod("myMethod", MyAnno.class.getClasses());
            MethodAnno methodAnno = myMethod.getDeclaredAnnotation(MethodAnno.class);

            System.out.println(methodAnno.methodNamett());
        }catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }/**
     * 查询所有方法
     */publicstaticvoidgetMethodAnno2() {
        Method[] myMethods = MyAnno.class.getMethods();for (Method method : myMethods) {if(method.isAnnotationPresent(MethodAnno.class)){
                MethodAnno methodAnno = method.getDeclaredAnnotation(MethodAnno.class);
                System.out.println(methodAnno.methodNamett());
            }
        }

    }

3. 构造方法上的注解

3.1 定义@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.CONSTRUCTOR)public @interfaceConstructorAnno {boolean isDefault();
}3.2 使用@ConstructorAnno(isDefault =true)publicMyAnno() {
    }@ConstructorAnno(isDefault =false)publicMyAnno(String name) {
    }3.3 调用/**
     * 根据指定名称获取
     */publicstaticvoidgetConAnno() {try {
            Constructor defaultConstructor = MyAnno.class.getDeclaredConstructor();
            ConstructorAnno constructorAnno=defaultConstructor.getDeclaredAnnotation(ConstructorAnno.class);
            System.out.println(constructorAnno.isDefault());

            Constructor Constructor = MyAnno.class.getDeclaredConstructor(String.class);
            ConstructorAnno constructorAnno2=Constructor.getDeclaredAnnotation(ConstructorAnno.class);
            System.out.println(constructorAnno2.isDefault());
        }catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }/**
     * 搜索所有构造方法
     */publicstaticvoidgetConsAnno2() {
        Constructor[] myConstructors = MyAnno.class.getConstructors();for (Constructor constructor : myConstructors) {if (constructor.isAnnotationPresent(ConstructorAnno.class)) {
                ConstructorAnno constructorAnno = constructor.getDeclaredAnnotation(ConstructorAnno.class);
                System.out.println(constructorAnno.isDefault());
            }
        }
    }

4. 类上的注解

4.1 定义@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)//可以修饰class 和intefacepublic @interfaceTypeAnno {
    String type();
}4.2 使用@TypeAnno(type="myTypeAnno")publicclassMyAnno {
}4.3 调用/**
     * 根据类名查询该类的
     */publicstaticvoidgetTypeAnno() {

        TypeAnno typeAnno = MyAnno.class.getDeclaredAnnotation(TypeAnno.class);
        System.out.println(MyAnno.class.isAnnotationPresent(TypeAnno.class));
        System.out.println(typeAnno.type());

    }/**
     * 查询包名下所有类
     */publicstaticvoidgetAnnoTypeAnno() {
        String basePackage ="com.myannotation";try {//先找到资源
            Enumeration<URL> enums = Thread.currentThread().getContextClassLoader().getResources(basePackage.replace(".","/"));while (enums.hasMoreElements()) {
                URL uri = enums.nextElement();if ("file".equals(uri.getProtocol())) {//是否是文件协议的文件
                    String dirsStr = uri.getFile();//获取文件路径
                    File dirsFile =new File(dirsStr);//创建File的文件夹对象if (dirsFile.isDirectory()) {
                        File[] files = dirsFile.listFiles();//获取该文件夹下所有文件for (File file : files) {if (file.isFile()) {
                                String classname = basePackage +"." + file.getName();
                                classname = classname.substring(0, classname.length() -6);//                                System.out.println(classname);
                                Class clazz = Class.forName(classname);if (clazz.isAnnotationPresent(TypeAnno.class)) {
                                    TypeAnno typeAnno = (TypeAnno) clazz.getDeclaredAnnotation(TypeAnno.class);
                                    System.out.println(typeAnno.type());
                                }
                            }
                        }
                    }
                }
            }

        }catch (IOException e) {
            e.printStackTrace();
        }catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

5. 局部变量的注解

publicvoidm(int a)  
@MyOwnAnnotation(some information)int b =5;  
}

目前无法通过反射的方法来获取局部变量上的注解(https://stackoverflow.com/questions/17237813/elementtype-local-variable-annotation-type)

6. 参数上的注解

6.1 定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)public @interface  ParamAnno {
    Stringvalue() ;
}6.2 使用publicstaticvoidmeMethod(@ParamAnno("myvalue") String name1,String name2){
        @LocalVariableAnno()
        String tt;
    }6.3 调用publicstaticvoidgetParamAnno() {try {
            Method method = MyAnno.class.getDeclaredMethod("meMethod", String.class, String.class);
            Annotation[][] paramss = method.getParameterAnnotations();for (Annotation[] parameterAnnotation : paramss) {for (Annotation annotation : parameterAnnotation) {if (annotation instanceof ParamAnno) {
                        ParamAnno param = (ParamAnno) annotation;
                        System.out.println(param.value());
                    }
                }
            }
        }catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }

7. 包注解

作用
1、为标注在包上Annotation提供便利;
2、声明包的私有类和常量;
* 3、提供包的整体注释说明

8. ANNOTATION_TYPE

待续

9. TYPE_PARAMETER和TYPE_USE

Java 8 学习笔记(一)

Spring中使用的注解

AliasFor

给注解起别名。

参考

https://www.cnblogs.com/peida/archive/2013/04/24/3036689.html

Java注解之Retention、Documented、Inherited介绍

关于java 注解中元注解Inherited的使用详解

Java注解学习三:package-info.java的使用

Spring4.2新特性(一)

  • 作者:Chase888
  • 原文链接:https://blog.csdn.net/a314773862/article/details/78941240
    更新时间:2022-06-27 13:17:57