查看原文
其他

通俗易懂地讲解 Java 的注解

脚本之家 2021-06-30

The following article is from 会点代码的大叔 Author 会点代码的大叔

  脚本之家

你与百万开发者在一起

本文经授权转自公众号 会点代码的大叔

如若转载请联系原公众号

今天,我们来聊聊 Java 的注解。



01

注解的概念



Annotation(注解):先看看官方给出的概念,注解是 Java 提供的一种对元程序中元素关联信息和元数据的途径和方法;这种解释让人看的一脸懵,通俗一点说,可以把注解看做是对人对物的标签,比如:


凶猛的狮子,温顺的兔子,木讷的程序员,帅气的大叔;这里的“凶猛”、“温顺”、“木讷”、“帅气”就是对各个事物的标签;


注解也是一种标签,是对 Java 代码的一种标签,可以告诉程序员被注解的代码是用来做什么的;


当然标签的内容可能跟实际情况有所出入,甚至背道而驰,比如【木讷的程序员】,实际上就是一个很差的标签,所以如果你在 Contrller 层的代码添加了一个 Service 的注解,同样也是一个很差的标签。



02

元注解



元注解是注解的注解,也就是对标签的描述。比如“木讷”、“帅气”只能用在人或动物身上,那么“只能用在人或动物身上”就是对“木讷”、“帅气”这两个标签的标签;恰好元注解中就有 @Target,表示修饰对象的范围,让我们详细看一下元注解都有哪些。


  • @Target:表示修饰对象的范围,注解可以作用于 packages、class、interface、方法、成员变量、枚举、方法入参等等,@Target可以指明该注解可以修饰哪些内容。

  • @Retention:时间长短,也就是注解在什么时间范围之内有效,比如在源码中有效,在 class 文件中有效,在 Runtime 运行时有效。

  • @Documented:表示可以被文档化,比如可以被 javadoc 或类似的工具生成文档。

  • @Inherited:表示这个注解会被继承,比如 @MyAnnotation 被 @Inherited 修饰,那么当 @MyAnnotation 作用于一个 class 时,这个 class 的子类也会被 @MyAnnotation 作用。



03

内置注解



Java 中最早内置了三种注解:


  • @Override:检查该方法是否是重载方法;如果父类或实现的接口中,如果没有该方法,编译会报错。

  • @Deprecated:已经过时的方法;如果使用该方法,会有警告提醒。

  • @SuppressWarnings:忽略警告;比如使用了一个过时的方法会有警告提醒,可以为调用的方法增加 @SuppressWarnings 注解,这样编译器不在产生警告。


JDK 7之后,又增加了三种:


  • @SafeVarargs:是一个参数安全类型注解,作用是告诉开发人员,参数可能会存在不安全的操作,要多注意一些;它会产生一个 unchecked 的警告;@SafeVarargs 注解只能用在可变长度参数的方法上,并且这个方法必须是 static 或 final 的,否则会出现编译错误。

  • @FunctionalInterface:表示是只有一个方法的接口,JDK 8 引入。

  • @Repeatable:表示注解的值可以有多个,比如我又帅气又幽默,这时候我同时有了“帅气”和“幽默”两个标签。



04

注解的使用场景



注解可以让编译器探测错误和警告;编译阶段可以利用注解生成文档、代码或做其他的处理;在代码运行阶段,一些注解还可以帮助完成代码提取之类的工作。


比如,使用过 Spring 框架的同学应该对 @Autowired 很熟悉了。使用 Spring 开发时,进行配置可以用 xml 配置文件的方式,现在用的更多的就是注解的方式。@Autowired 可以帮助我们注入一个定义好的 Bean。


@Autowired 的核心代码大概是这样的,作用就是 Spring 可以提取到使用 @Autowired 修饰的字段或方法做注入:


private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { //省略...... do { //省略......
//通过反射,获取这个类的所有字段,并遍历所有字段 ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() { //遍历字段的所有注解 @Override public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { //如果字段使用了 @Autowired AnnotationAttributes ann = findAutowiredAnnotation(field); if (ann != null) { if (Modifier.isStatic(field.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static fields: " + field); } return; } boolean required = determineRequiredStatus(ann); //先放到 currElements 中,后面一起集中处理 currElements.add(new AutowiredFieldElement(field, required)); } } });
//省略...... } while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);}
//统一处理,也就是注入的源码我就不贴了

- END -



更多精彩


在公众号后台对话框输入以下关键词

查看更多优质内容!


女朋友 | 大数据 | 运维 | 书单 | 算法

大数据 | JavaScript | Python | 黑客

AI | 人工智能 | 5G | 区块链

机器学习 | 数学 | 送书

●  2020年第一个候选Java增强提案已出现

●  脚本之家粉丝福利,请查看!

●  人人都欠微软一个正版?

● 18 个示例带你掌握 Java 8 日期时间处理!

 Java中的对象都是在堆上分配的吗?

● 如何优雅的处理 Java 异常,可以参考这些建议

● 2020 Java生态系统报告出炉

Java:实现文件批量导入导出实践

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存