美文网首页alreadyjava
Java的注解Annotation

Java的注解Annotation

作者: 小虎哥的技术博客 | 来源:发表于2022-08-01 15:26 被阅读0次

    注解使代码简单易读,提供编译器类型检查,并且可以通过注解构造代码处理工具。

    日常开发中我们会遇到很多注解,如@RestController@GetMapping@Autowired@Service等等。
    那这些注解是怎么定义的?怎么使用的?为什么要这些注解?

    接下来我们从基础知识来慢慢揭开注解的面纱。

    注解的基础知识

    注解的格式

    注解以@符号开头,如下:

    @Entity
    

    注解被用在什么地方

    注解可以应用于声明:类、字段、方法和方法参数等。如下:

    @Author(
       name = "Benjamin Franklin",
       date = "3/27/2003"
    )
    class MyClass { ... }
    
    @Override
    void mySuperMethod() { ... }
    
    class UnmodifiableList<T> implements 
        @Readonly List<@Readonly T> { ... }
    

    定义注解

    @interface关键字定义注解,和定义接口有点像,多了个@符号。

    注解里面的属性跟接口方法有点像,但没有方法体。属性可以有默认值,如currentRevision默认值为1。

    // 注解 类注释
    @Retention(value = RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface ClassPreamble {
        String name();
    
        String author();
    
        String date();
    
        int currentRevision() default 1;
    }
    

    使用注解

    @ClassPreamble(
            name = "学生类",
            author = "llh",
            date = "2022-08-01",
            currentRevision = 2)
    public class Student {
    
    }
    

    spring 的@Service是这么定义的。

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Service {
        @AliasFor(annotation = Component.class)
        String value() default "";
    }
    

    元注解

    自定义注解一定要用到元注解,元注解就是定义注解的注解。有以下五个元注解。

    @Retention

    @Retention注解指定标记注解的存储方式:

    • RetentionPolicy.SOURCE:注解只保留在源代码级别,编译器会忽略它。
    • RetentionPolicy.CLASS:注解在编译时由编译器保留,但被 Java 虚拟机 (JVM) 忽略。
    • RetentionPolicy.RUNTIME:注解由 JVM 保留,以便运行时环境使用。

    @Target

    @Target注解标记另一个注解,以限制该注解可以应用于哪种Java元素。目标注释指定以下元素类型之一作为其值:

    • ElementType.ANNOTATION_TYPE:可以应用于注释类型。
    • ElementType.CONSTRUCTOR:可以应用于构造函数。
    • ElementType.FIELD:可以应用于字段或属性。
    • ElementType.LOCAL_VARIABLE:可以应用于局部变量。
    • ElementType.METHOD:可以应用于方法级别的注释。
    • ElementType.PACKAGE:可以应用于包声明。
    • ElementType.PARAMETER:可以应用于方法的参数。
    • ElementType.TYPE:可以应用于类、接口(包括注释类型)或枚举声明

    @Inherited

    @Inherited注解表示注解类型可以继承自超类。(默认情况下不是这样。)当用户查询注解类型并且该类没有该类型的注解时,将查询该类的超类的注解类型。此注释仅适用于类声明。

    @Documented

    @Documented注解表示无论何时使用指定的注解,都应使用 Javadoc 工具记录这些元素

    @Repeatable

    在 Java SE 8 中引入,表示标记的注解可以多次应用于同一个声明或类型使用。

    编写注解处理器

    如果没有用于读取注解的工具,那么注解不会比注释更有用。使用注解中一个很重要的部分就是,创建与使用注解处理器。Java 拓展了反射机制的 API 用于帮助你创造这类工具。

    如下是个很简单注解处理工具,利用反射获取类的注解,然后打印注解信息。

    public class Demo {
        public static void main(String[] args) {
            Class<?> c = Student.class;
            ClassPreamble annotation = c.getAnnotation(ClassPreamble.class);
            System.out.println(annotation.name());
            System.out.println(annotation.author());
            System.out.println(annotation.date());
            System.out.println(annotation.currentRevision());
        }
    }
    

    模拟 Spring 的 @Service

    自定义MyService注解

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface MyService {
        String value() default "";
    }
    
    public interface UserService {
    }
    
    @MyService("userService")
    public class UserServiceImpl implements UserService {
    }
    

    这里模拟Spring容器扫描有MyService注解的类,并自动生成该类的一个实例对象保存到容器中。

    public class Demo {
        public static void main(String[] args) {
            try {
                // 模拟 spring 容器
                Map<String, Object> map = new ConcurrentHashMap<>();
    
                // 模拟 扫描所有有MyService注解的类
                Class<?> c = UserServiceImpl.class;
                MyService annotation = c.getAnnotation(MyService.class);
                if (annotation != null) {
                    // 模拟 有MyService注解的类生成该类的一个实例对象
                    Object obj = c.newInstance();
    
                    // 模拟 保存到容器中 key就是注解的值 userService
                    map.put(annotation.value(), obj);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    实际要比这个复杂的多得多,我这里就是示意说明一下注解的作用,让大家容易理解。

    结语

    注解我们日常开发经常用,但是很多同学从来没有自己手动去创建过一个自定义的注解类。

    1万小时定律:1万小时的锤炼是任何人从平凡变成世界级大师的必要条件。但是写1万小时的代码你就能变成大师吗?非也!不要重复性的工作,要思考要深入!

    关注微信公众号:小虎哥的技术博客,每天一篇文章,让你我都成为更好的自己

    相关文章

      网友评论

        本文标题:Java的注解Annotation

        本文链接:https://www.haomeiwen.com/subject/aosrwrtx.html