开发者

Java中的注解详解(Annotation)

开发者 https://www.devze.com 2025-03-15 12:26 出处:网络 作者: 小宝945
目录一、元注解Java 中的元注解二、Java 中内置的三大注解三、自定义注解四、反射注解五、注解的作用六、总结所有的注解类型都继承自 java.lang.annotation.Annotation 接口。
目录
  • 一、元注解
    • Java 中的元注解
  • 二、Java 中内置的三大注解
    • 三、自定义注解
      • 四、反射注解
        • 五、注解的作用
          • 六、总结

            所有的注解类型都继承自 java.lang.annotation.Annotation 接口。

            注解(Annotation)是一种引用数据类型。编译之后也是生成 xxx.class 文件。

            一个注解准确意义上来说,只不过是一种特殊的注释而已,如果没有解析它的代码,它可能连注释都不如。

            解析一个类或者方法的注解往往有两种形式

            一种是编译期直接的扫描。=====> @Retention(RetentionPolicy.SOURCE)

            • 编译器的扫描指的是编译器在对 java 代码编译字节码的过程中会检测到某个类或者方法被一些注解修饰,这时它就会对于这些注解进行某些处理。典型的就是 @Override 注解。
            • 这一种情况只适用于那些编译器已经熟知的注解类,比如 JDK 内置的几个注解,而你自定义的注解,编译器是不知道你这个注解的作用的,当然也不知道该如何处理,往往只是会根据该注解的作用范围来选择是否编译进字节码文件,仅此而已。

            一种是运行期反射。====> @Retention(RetentionPolicy.RUNTIME)

            一、元注解

            • 元注解是用于修饰注解的注解,通常用在注解的定义上。
            • 元注解一般用于指定某个注解生命周期以及作用目标等信息。

            Java 中的元注解

            @Target:注解的作用目标

            @Documented
            @Retention(RetentionPolicy.RUNTIME)
            @Target(ElementType.ANNOTATION_TYPE)
            public @interface Target {
            	/**
             	* Returns an array of the kinds of elements an annotation interface
             	* can be applied to.
             	* @return an array of the kinds of elements an annotation interface
             	* can be applied to
             	*/
            	ElementType[] value();
            }
            • ElementType.TYPE:允许被修饰的注解作用在类、接口和枚举上
            • ElementType.FIELD:允许作用在属性字段上
            • ElementType.METHOD:允许作用在方法上
            • ElementType.PARAMETER:允许作用在方法参数上
            • ElementType.CONSTRUCTOR:允许作用在构造器上
            • ElementType.LOCAL_VARIABLE:允许作用在本地局部变量上
            • ElementType.ANNOTATION_TYPE:允许作用在注解上
            • ElementType.PACKAGE:允许作用在包上

            @Retention:注解的生命周期

            @Documented
            @Retention(RetentionPolicy.RUNTIME)
            @Target(ElementType.ANNOTATION_TYPE)
            public @interface Retention {
               /**
             	* Returns the retention policy.
              	* @return the retention policy
            	*/
            	RetentionPolicy value();
            }
            • RetentionPolicy.SOURCE:当前注解编译期可见,不会写入 class 文件
            • RetentionPolicy.CLASS:类加载阶段丢弃,会写入 class 文件
            • RetentionPolicy.RUNTIME:永久保存,可以反射获取

            @Documented:注解是否应当被包含在 JavaDoc 文档中

            @Inherited:是否允许子类继承该注解

            二、Java 中内置的三大注解

            • @Override
            @Target(ElementType.METHOD)
            @Retention(ReAaqgUWVVDtentionPolicy.SOURCE)
            public @interface Override {
            }

            它没有任何的属性,所以并不能存储任何其他信息。它只能作用于方法之上,编译结束后将被丢弃。

            仅被编译器可知,编译器在对 java 文件进行编译成字节码的过程中,一旦检测到某个方法上被修饰了该注解,就会去匹对父类中是否具有一个同样方法签名的函数,如果不是,自然不能通过编译。

            • @Deprecated
            @Documented
            @Retention(RetentionPolicy.RUNTIME)
            @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
            public @interface Deprecated {
                String since() default "";
                boolean forRemoval() default false;
            }

            可以修饰所有的类型,作用是,标记当前的类或者方法或者字段等已经不再被推荐使用了,可能下一次的 JDK 版本就会删除。

            • @SuppressWarnings

            三、自定义注解

            语法格式:

            [修饰符列表] @interfa编程客栈ce 注解类型名{
            	类型 属性() [defauult 值];
            }
            // 样例
            @Target(ElementType.TYPE)
            @Retention(RetentionPolicy.RUNTIME)
            public @interface MyAnnotation {
                String name() default "gdb";
                String[] phoneNumbers() default {};
            }

            注解当中的属性类型可以是:byte short int long float double boolean char String Class 枚举类型以及以上每一种的数组形式。

            四、反射注解

            要求必须使用 @Retention(RetentionPolicy.RUNTIME),这样该注解才能够被反射到。

            例子:反射类上的 @MyAnnotation 注解。

            • 1.编写自己的注解:
            package annotation1;
            
            import java.lang.annotation.ElementType;
            import java.lang.annotation.Retention;
            import java.lang.annotation.RetentionPolicy;
            import java.lang.annotation.Target;
            
            @Target(ElementType.TYPE)
            @Retention(RetentionPolicy.RUNTIME)
            public @interface MyAnnotation {
                String name() default "gdb";
                String[] phoneNumbers() default {};
            }	
            • 2.在类上使用自己的注解:
            package annotation1;
            
            @MyAnnotation(name = "zhangsan", phoneNumbers = {"123456", "654321"})
            public class MyAnnotationTest {
            
            }
            • 3.通过反射机制来获取指定类上的注解信息:
            package annotation1;
            
            import java.util.Arrays;
            
            public class ReflectAnnotation {
                public static void main(String[] args) throws Exception {
                    //获取类
                    Class<?> c = Class.forName("annotation1.MyAnnotationTest");
                    //判断类上面是否有 @MyAnnotation
                    if (c.isAnnotationPresent(MyAnnotation.class)){
                        //获取注解对象
                        MyAnnotation myAnnotation = (MyAnnotation)c.getAnnotation(MyAnnotation.class);
                        //获取注解对象的属性和调用接口没有区别
                        System.out.println(myAnnotation.name() + ", " + Arrays.toString(myAnnotation.phoneNumbers()));
                    }
                    //判断 Date 类上面是否有 @MyAnnotation 这个注解。
                    Class<?> s = Class.forName("java.lang.String");
                    System.out.println(s.isAnnotationPresent(MyAnnotation.class));
                }
            }
            

            五、注解的作用

            注解在程序当中等同于一种标记,如果这个元素上有这个注解怎么办,没有这个注解怎么办。

            应用场景:假设有这样一个注解,叫做 @Id,这个注解只能出现在www.devze.com类上面,当这个类上有这个注解的时候,要求这个类中必须有一个 int 类型的 id 属性。如果没有这个属性就报异常。如果有这个属性就正常执行。

            • 1.编写 @Id 注解:
            package annotation1;
            
            public class NotHasIdException extends RuntimeException{
                public NotHasIdException() {
                }
            
                public NotHasIdException(String message) {
                    super(message);
                }
            }
            • 2.编写异常类:
            package annotation1;
            
            public class NotHasIdException extends RuntimeException{
                public NotHasIdException() {
                }
            
                public NotHasIdException(String message) {
                    super(message);
                }
            }
            
            • 3.编写使用 @Id 注解的类:
            package annotation1;
            
            @Id
            public class IdAnnotationTest {
                int id;
            }
            
            • 4.通过反射机制来判断是否正确:
            package annotation1;
            
            import java.lang.reflect.Field;
            
            public class ReflectAnnotation {
                public static void main(String[] args) throws Exception {
                    //获取类
                    Class<?> c = Class.forName("annotation1.IdAnnotationTest");
                 android   //判断类上面是否有 @Id 注解
                    if (c.isAnnotationPresent(Id.class)){
                        //当一个类上面有 @Id 注解的时候,要求类中必须存在 int 类型的id属性。
                        //如果没有int类型的id属性则报异常。
                        //获取类的所有属性
                        Field[] fields = c.getDeclaredFields();
                        boolean isOK = false;
                        for(Field field : fields){
                            if("id".equals(field.getName()) && "int".equals(field.getType().getSimpleName())){
                                isOK = true;
                           python     break;
                            }
                        }
                        //判断是否合法
                        if (!isOK)
                            throw new NotHasIdException("被@Id注解标注的类没有int类型的id属性!!!");
                    }
                }
            }
            

            六、总结

            • 如果一个注解的属性的名字是 value,并且只有一个属性的话,在使用的时候,该属性名可以省略。
            • 如果属性是一个数组,如果数组中只有一个元素,大括号可以省略。

            以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

            0

            精彩评论

            暂无评论...
            验证码 换一张
            取 消

            关注公众号