为什么Java要用注解,那么这些注解有哪些作用呢
注解的英文名叫"Annotation",是 Java 中给类、方法以及成员变量等元素增加元数据的方式。换言之注解就是用于描述这些元素的。
元数据一词从单词 metadata 译来,意为"描述数据的数据"。
注解和注释不同的是,注解会被 Java 编译器处理而非跳过。
注解是在JDK5.0版本开始引入的,它可以在编译期使用预编译工具进行处理, 也可以在运行期使用 Java 反射机制进行处理。注释可以用于创建 Javadoc,跟踪代码中的依赖性,甚至执行基本编译时检查。本质上,Annotion是一种特殊的接口,程序可以通过反射来获取指定程序元素的 Annotion 对象,通过 Annotion 对象来获取注解里面的元数据。
相比上来就给大家介绍注解的各种概念,它都有哪些作用外,我更希望把自己带入到一个 Java 小白的身份从零开始了解注解。我们通过"认识注解、使用注解"开始了解注解,随后带出 Java 原生自带的注解以及如何自定义注解,在编写自定义注解的时候顺便通过使用元注解把元注解的概念介绍一下,最后再来说注解都有哪些作用,以及使用注解带来的收益时需要付出什么代价。
本文内容大纲如下:
初识注解
Java 注解的简写形式如下:@Entity 复制代码
@ 符号告诉编译器这是一个注解, @ 字符后面的名称是注解的名称。在上面的示例中,注解名称是 Entity。
注解还可以包含为其设置值的元素,类似注解的一个属性。下面是一个带元素的 PostMapping 注解示例。@PostMapping(path = "/") 复制代码
上面的 PostMapping 注解包含一个名为 path 的元素,我们为其赋值为 "/"。设置元素值的语法是在注解名称后的括号内进行设置。
一个注解可以包含多个元素,比如 PostMapping 注解就可以通过consumes元素,指定接收的请求体的格式为application/json@PostMapping(path = "/", consumes = MediaType.APPLICATION_JSON_VALUE) 复制代码
当然,PostMapping 注解能设置哪些元素的值,也是根据 PostMapping 注解的定义来的。public @interface PostMapping { // 省略其他元素的定义...... @AliasFor( annotation = RequestMapping.class ) String[] path() default {}; @AliasFor( annotation = RequestMapping.class ) String[] consumes() default {}; // ...... } 复制代码
如果注解只包含一个元素,那么按照约定惯例,会把该元素命名成"value":@InsertNew(value = "yes") 复制代码
当注解只包含一个名为 value 的元素时,使用注解时我们可以省略元素名称,只提供元素值。@InsertNew("yes") 复制代码使用注解
Java 的注解可以应用在类、接口、方法、方法的参数、成员变量和方法内的局部变量之上,比如在类上应用注解,就是把注解放在类声明之上。@Entity @Table(name = "coffees") public class Coffee implements Serializable { // ...... } 复制代码
下面这个例子在类、成员变量、成员方法、方法参数上都应用了注解。@RestController @RequestMapping("/order") @Slf4j public class CoffeeOrderController { @Autowired private CoffeeOrderService orderService; @Autowired private CoffeeService coffeeService; /** * 创建Coffee订单 * * @param newOrder * @return CoffeeOrder */ @PostMapping(path = "/", consumes = MediaType.APPLICATION_JSON_VALUE) public CoffeeOrder create(@RequestBody NewOrderRequest newOrder) { // ... } } 复制代码
上面是一个典型的 Spring MVC 的 Controller API 处理方法,如果你对 Spring 框架还不太熟悉,可以先不管这些注解什么意思,这里主要是演示一下注解可以用在哪里。在Java程序的这些成员上都可以加上注解,为成员添加元数据。Java 内置的注解
Java 带有三个内置注解,可以直接被编译器处理,用于为 Java 编译器提供指令。这些注解是:@Override@Deprecated@SupressWarning@Override
@Override 注解用于标注方法,它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们在一个没有覆盖父类方法的方法上应用 @Override 注解时,Java编译器会告警。public class MySuperClass { public void doTheThing() { System.out.println("Do the thing"); } } public class MySubClass extends MySuperClass{ @Override public void doTheThing() { System.out.println("Do it differently"); } } 复制代码
在覆盖了父类方法的子类方法上使用 @Override 注解并不是必需的。不过,使用了@Override 注解的方法,编译器在编译时会去父类找相同的方法签名,验证方法覆盖是否真实存在。
使用@Override 注解的一个好处是--比如说有人在项目里修改了父类的被子类覆盖的方法,子类覆盖方法上不使用 @Override 注解的话编译器是不会提示出子类方法未覆盖父类方法的,可能会导致调用方无法正确调用到子类方法的问题,这时就显出 @Override 的重要性了。@Deprecated
@Deprecated 注解用于将类、方法或字段标记为已弃用,这意味着不推荐再使用它。如果你的代码使用了不推荐使用的类、方法或字段,编译器在编译时会产生一条 Warning 级别的告警。@Deprecated public class MyComponent { } 复制代码
在类声明上方使用 @Deprecated 注解将该类标记为已弃用。 还可以在方法和字段声明上方使用@Deprecated 注解,将方法或字段标记为已弃用。 当使用 @Deprecated 注解时,最好也使用相应的 @deprecated 注解,该注解用于JavaDoc ,一般使用它来解释为什么不推荐使用以及应该改用什么。@Deprecated /** * @deprecated Use MyNewComponent instead. */ public class MyComponent { @Deperecated // @deprecated Use MyNewComponent"s printComponentName instead. public void printComponentName() { System.out.println("MyComponent") } } 复制代码@SupressWarning
@SuppressWarnings 用于关闭对类、方法、成员编译时产生的特定警告。 @SuppressWarnings 不是一个标记注解。它有一个类型为 String[] 的数组成员,这个数组中存储的是要关闭的告警类型。对于 javac 编译器来讲,对 -Xlint 选项有效的警告名也同样对 @SuppressWarings 有效,同时编译器会忽略掉无法识别的警告名。@SuppressWarnings({"rawtypes", "unchecked"}) public class SuppressWarningsAnnotationDemo { static class SuppressDemo { private T value; public T getValue() { return this.value; } public void setValue(T var) { this.value = var; } } @SuppressWarnings({"deprecation"}) public static void main(String[] args) { SuppressDemo d = new SuppressDemo(); d.setValue("London"); System.out.println("Place:" + d.getValue()); } } 复制代码自定义注解
下面让我们自己定义一个注解。public @interface MyAnnotation { String value(); String name(); int age(); String[] newNames(); } 复制代码
使用 @interface 关键字来声明一个注解,注解的声明有点类似于接口声明,其中的每一个方法实际上是声明了一个注解的元素。方法的名称就是元素的名称,返回值类型就是元素的值类型(返回值类型只能是基本类型、Class、String、enum)。这个例子定义了一个名为 MyAnnotation 的注解,它有四个元素。@MyAnnotation( value="123", name="Jacob", age=37, newNames={"Jenkov", "Peterson"} ) public class MyClass { // ... } 复制代码
现在使用 @MyAnnotation 必须像上面这个例程中的这样,为其的所有元素指定值。但其实是可以在声明注解时给元素设置默认值的。注解元素的默认值
在定义注解的时候可以为元素指定默认值。这样元素就变成了可选的,在使用的时候被省略则直接使用其默认值。下面是在注解定义里如何给元素指定默认值的例子:@interface MyAnnotation { String value() default ""; String name(); int age(); String[] newNames(); } 复制代码
现在我们可以在使用 MyAnnotation 注解时选择省略 value 元素,这样注解会默认使用 value 元素的默认值。如下所示:@MyAnnotation( name="Jakob", age=37, newNames={"Jenkov", "Peterson"} ) public class MyClass { } 复制代码
像上面这个例子,在注解的使用中我们并没有指定其 value 元素的值。元注解
元注解是用于修饰注解的注解,在注解的定义中使用,例如:@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { } 复制代码
这是 @Override 注解的定义,可以看到其中的 @Target,@Retention 两个注解就是『元注解』,元注解一般用于指定注解的生命周期以及作用目标等信息。 Java 中有以下几个元注解:@Retention:注解的生命周期或者叫保留策略@Target:注解的作用目标@Inherited:是否允许子类继承该注解@Documented:注解是否应当被包含在 JavaDoc 文档中@Retention
我们可以为上面自定义的注解 MyAnnotation 指定它是否在运行时可用,以便能通过反射进行检查。通过在注解 MyAnnotation 的定义中使用 @Retention 元注解来做到这一点。import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation { String value() default ""; } 复制代码
添加到 MyAnnotation 定义上的元注解。@Retention(RetentionPolicy.RUNTIME) 复制代码
会指示 Java 编译器和 JVM 当前注解在运行时可以通过反射获取到。RetentionPolicy 类表示注解的保留策略,包含三个两个可以使用的值:RetentionPolicy.RUNTIME 表示注解永久保存,在运行时可以通过反射获取。RetentionPolicy.CLASS 表示注解存储在 .class 文件中,在类加载阶段被丢弃,运行时不可用。RetentionPolicy.SOURCE 表示注解仅在源代码中可用,在 .class 文件和运行时中不可用。
在定义注解时如果不指定注解的任何保留策略,RetentionPolicy.CLASS 就是默认的保留策略。如果创建的注解是与扫描代码的构建工具一起使用,则可以使用保留策略 RetentionPolicy.SOURCE,这样就会避免 .class 文件受到不必要的污染。@Target
上面例子第一的 MyAnnotation 注解并没有标明该注解的作用目标,是能作用在类上,方法上,还是字段上。如果要限制注解的可作用目标的话,就需要在注解定义中使用 @Target 元注解来进行限制。
下面我们给自己定义的 MyAnnotation 加上 @Target ,限制它只能注解方法上。import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target({ElementType.METHOD}) public @interface MyAnnotation { String value(); } 复制代码
ElementType 包含以下可用的枚举值:ElementType.TYPE:允许被修饰的注解作用在类、接口和枚举上ElementType.FIELD:允许作用在属性字段上ElementType.METHOD:允许作用在方法上ElementType.PARAMETER:允许作用在方法参数上ElementType.CONSTRUCTOR:允许作用在构造器上ElementType.LOCAL_VARIABLE:允许作用在本地局部变量上ElementType.ANNOTATION_TYPE:允许作用在注解上ElementType.PACKAGE:允许作用在包上
大部分枚举值的名称都是自解释的,可以通过字面单词意思看出来。有两个需要额外说明下,ElementType.ANNOTATION_TYPE 表示注解只能用于注解其他注解。在 @Target 和@Retention 这些元注解的定义里我们能看到使用的正式这个枚举值。@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); } 复制代码
ElementType.TYPE 表示注解能用于任何类型,可以是类、接口、枚举,包括注解。@Inherited
@Inherited 表示自动继承注解类型。 如果注解声明中存在 @Inherited 元注解,则注解所修饰类的所有子类都将会继承此注解。java.lang.annotation.Inherited @Inherited public @interface MyAnnotation { } --- @MyAnnotation public class MySuperClass { ... } --- public class MySubClass extends MySuperClass { ... } 复制代码
在这个例子中,MySubClass 会从父类 MySuperClass 自动继承 MyAnnotation 注解。@Documented
@Documented 元注解被用于告知 JavaDoc 生成工具,当前注解需要在使用它的类的文档中显示。import java.lang.annotation.Documented; @Documented public @interface MyAnnotation { } 复制代码@MyAnnotation public class MySuperClass { ... } 复制代码
当为 MySuperClass 生成 JavaDoc 的时候, @MyAnnotation 注解会被包含其中。 @Documented 这个元注解并不会经常用到,当我们看源码的时候遇到它后,能知道它是干什么用的就行了。Java 里注解的用途
在 Java 里注解有许多用途,可以归纳为三类:编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查,编译器可以使用注解来检测错误或抑制警告。编译时和部署时的处理:程序可以处理注解信息以生成代码,XML 文件等。运行时处理:可以在运行时检查某些注解并处理。
作为 Java 程序员,尤其是编程十几年年的老手,多多少少都曾经历过被各种配置文件(xml、properties)支配的恐惧。过多的配置文件会使得项目难以维护。使用注解可以减少配置文件或代码,是注解最大的用处,现在 Spring 家族的 SpringBoot 就是靠注解维护各种 Bean 组件的,让开发中者不再用XML指定各种Java Bean 的路径、名称等属性,减少了不少项目配置的步骤,从而让Java项目的开发提速了不少。
原文:https://juejin.cn/post/7164655191201939486
单日入园人数超10000人!绍兴鲁迅故里的年味回来了金虎送春归,玉兔迎春来。癸卯年正月初一,你在绍兴吗?被疫情偷走了三年的热闹春节,终于在2023年,回来了!鲁迅故里大红灯笼高高挂起,久违的人山人海给沉寂已久的古城绍兴带来浓浓的人间
任程伟12岁丧父,26岁娶黄蕾住7年地下室,成名后更爱患难妻1996年,面对女友黄蕾的不停催婚,演艺事业还没有太大起色的任程伟,只好无奈地对她说我也想结婚,可我连500块钱都没有,连婚礼都办不起,我怎么娶你啊?看到他一脸无奈和没办法的表情,
推荐关于人生哲理的10部优秀电影星期五言从电影中获取对人生的感悟其实是一条捷径,因为电影是艺术真实,是假定的人生。但必须是优秀的电影,才能获取更深刻的人生哲理,如果从三流电影中获取,或许是歪门邪道。人生哲理是什么
春晚里的中国丨创新遇上文化满庭尽是芳华碇步桥飒飒摇摆,节奏欢快灵动千年古韵遗音,点亮非遗文化瑰宝神兽遇见神兽,炫动舞台惟妙惟肖除夕之夜,2023兔年春晚在一片欢乐吉祥喜气洋洋的氛围中,如约与观众见面。春晚年年有,年年有
文化和旅游部再次提醒广大游客增强安全意识,平安健康出游2023年春节假期迎来第三天,文化和旅游部再次提醒广大游客增强安全意识,平安健康出游。一远离无安全保障的危险区域。旅途中注意远离濒水崖边河道等危险区域,关注当地有关安全提示,遵守相
闽北中心搬迁后,建阳人口持续上升,成为福建最牛的三线城市闽北新中心建阳,自南平政府搬迁以来,人口持续上升至34。3万人,兴建了城际铁路,大型城市综合体,和南平体育中心等配套项目。而被搬迁延平区,自2017年人口达到47。9万人以后,已呈
拒绝续约!魔笛欲为金钱逃离皇马,1亿欧元前往沙特联手C罗相比于上赛季来说,本赛季皇马的表现只能说是一般,但这只是就球队竞技状态而言,毕竟在联赛及欧冠都有极大概率争冠。可是皇马给外界的感觉却有点力不从心,之所以如此最主要的就是因为中场实力
拉祜村寨踏歌声老达保村口的乐谱雕塑。虎遵会摄(人民视觉)独具拉祜族特色的织绣挂饰装点着民居,传递着浓浓年味。虎遵会摄(人民视觉)身穿拉祜族特色服饰的孩子们。虎遵会摄(人民视觉)老达保村民们日常弹
香港故宫首次邂逅年味儿马子倩文摄说到今年春节香港最热门的打卡点,香港故宫文化博物馆(以下简称香港故宫)一定少不了。香港故宫于2022年7月2日正式对公众开放,博物馆内有9个展厅,展出来自故宫博物院精选的
本特安东尼踢球就是为炫技而炫技,花里胡哨但过不了人直播吧1月24日讯近日,前英格兰国脚达伦本特在参加talkSPORT节目时谈到了曼联前锋安东尼,他对这名巴西国脚进行批评。本特表示他踢球大部分时间要么在炫技要么耍花架子,没有什么实
今年春节怎么耍成都?攻略看这里!瑞兔送福一帆风顺年年好,万事如意步步高今天是大年初三大家都在哪里过的年是不是跟小编一样在成都愉快地玩耍呀你们春节假期打算去哪里玩呢这里有一份成都出游攻略,快快收下!无论你是想去赏灯