前言
Annotation是 JDK 5.0 开始引入的新技术。
从 JDK5 开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
什么是注解?
我最开始听到这个词的时候也和大多人一样,以为和注释一样,是一段辅助性的文字,其实不然。
“注释”是给人看的,“注解”不仅是给人看的,也是可以给程序看,甚至可以被其他程序读取。
注解的概念
注解,可以看作是对一个类或方法的一个扩展的模版,每个类或方法按照注解类中的规则,来为类或方法注解不同的参数,在用到的地方可以得到不同的类或方法中注解的各种参数与值。
Java注解(Annotation)是一种元数据,它提供了在代码中添加标记和元数据的方式。注解本身并不会改变代码的行为,但可以在编译时、运行时或者在运行时通过反射机制来获取注解信息,从而实现一些特定的功能。
从 JDK5 开始,java增加了对元数据(描述数据属性的信息)的支持。其实就是代码里的特殊标志,这些标志可以在编译,类加载,运行时被读取,并执行相应的处理,以便于其他工具补充信息或者进行部署。
注解的作用
1、提供编译时检查功能:通过使用注解,可以让编译器在编译时检查代码的一些约束和限制,比如检查方法参数的合法性、检查类或方法是否遵循一些规范等。
2、提供运行时检查功能:通过使用注解,可以在程序运行时对代码进行检查,比如检查权限、检查输入数据的合法性等。
3、自动生成代码:通过使用注解,可以生成一些代码,比如自动生成代码文档、自动生成测试用例等。
4、用于框架和工具:Java注解在很多框架和工具中得到广泛应用,比如Spring框架中的注解、JUnit测试框架中的注解等。
注解可以被其他程序读取
注解的格式
@注解名(属性名 = 属性值, 属性名 = 属性值, ...)
修饰符 返回值类型 方法名(参数列表) {
// 方法体
}
其中 @注解名
表示使用某个注解,注解名需要使用 @
符号进行声明。
注解后面的括号中可以包含一些属性名和属性值,格式为 属性名 = 属性值
,多个属性之间可以用逗号隔开。
例如:
@SuppressWarnings(value="all")
注解的使用
-
类和接口:可以用于标记类和接口的特性和属性,比如 @Deprecated 注解用于标记已经过时的类或方法;
-
方法:可以用于标记方法的特性和属性,比如 @Override 注解用于标记方法覆盖了父类中的方法;
-
字段和变量:可以用于标记字段和变量的特性和属性,比如 @NonNull 注解用于标记变量不允许为 null;
-
构造方法:可以用于标记构造方法的特性和属性,比如 @Autowired 注解用于自动装配依赖对象;
-
参数:可以用于标记方法参数的特性和属性,比如 @RequestParam 注解用于标记请求参数;
-
包:可以用于标记包的特性和属性,比如 @ComponentScan 注解用于指定需要扫描的包;
-
注解本身:可以用于定义新的注解,比如 @Retention 注解用于指定注解的保留策略;
总的来说,Java 注解可以附加在package、class、method、field等上面,相当于给他们添加了额外的辅助信息。注解用于标记和描述代码的各种特性和属性,提供了一种元数据的方式,可以在编译时、运行时或者在运行时通过反射机制来获取注解信息,从而实现一些特定的功能。
内置注解
Java 内置注解是指在 Java 标准库中已经定义好了的注解,这些注解可以用于标记和描述代码的特性和属性,提供了一种元数据的方式,用于编写更加规范、易于维护的代码。
以下是 Java 内置注解的详细说明:
-
@Override:定义在 java.lang.Override 中,打算重写一个方法,用于标记方法覆盖了父类中的方法,可以让编译器在编译时检查是否正确地覆盖了方法。
-
@Deprecated:定义在 java.lang.Deprecated 中,用于标记已经过时的类或方法,可以提醒开发者不要再使用该类或方法。(不推荐程序员使用,但可以使用,或者存在更好的方式)
-
@SuppressWarnings:定义在 java.lang.SuppressWarnings 中,用于抑制编译器产生的警告,可以让编译器在编译时忽略某些警告信息。
与前两个注解有所不同,你需要添加一个参数才可以正常使用,这些参数都是定义好了的,我们选择性使用就行。
-
@SuppressWarnings(“all”)
-
@SuppressWarnings(“unchecked”)
-
@SuppressWarnings(value={“unchecked”,”deprecation”})
-
等等……
-
-
@SafeVarargs:用于标记方法中使用了可变参数,并且不会出现类型安全问题。
-
@FunctionalInterface:用于标记一个接口是函数式接口,即只包含一个抽象方法的接口。
元注解
元注解是指用于注解其他注解的注解,也就是对注解进行注解的注解。
元注解可以用于指定注解的作用范围、生命周期、作用目标等信息,可以帮助开发者更加精细地控制注解的行为。
Java 定义了 4 个标准的 meta-annotation 类型,它们被用来对其他 annotation 类型作说明。这些类型和它们所支持的类在 java.lang.annotation 包中可以看到。以下是 Java 元注解的详细说明:
-
@Retention:表示需要在什么级别保存该注释信息,用于指定注解的生命周期,包括 SOURCE、CLASS 和 RUNTIME 三种生命周期。其中,SOURCE 表示注解只在源码级别可见,不会被编译到字节码中;CLASS 表示注解在编译时可见,但在运行时不可见;RUNTIME 表示注解在运行时可见,可以通过反射机制来获取注解信息。
(SOURCE < CLASS < RUNTIME)
-
@Target:用于指定注解的作用目标,包括类、方法、字段、参数等。可以同时指定多个目标,用花括号分隔。
-
@Inherited:用于指定注解是否可以被子类继承。如果一个注解被 @Inherited 标记,那么它的子类会自动继承该注解。
-
@Documented:用于指定注解是否包含在 JavaDoc 中。如果一个注解被 @Documented 标记,那么它的信息会包含在 JavaDoc 中。
-
@Repeatable:用于指定注解是否可重复。该注解只能用于注解声明上,如果一个注解被 @Repeatable 标记,那么它可以多次应用于同一个元素。
自定义注解
Java 自定义注解是一种特殊的注释,它可以被应用于 Java 代码中的类、方法、属性等元素上,用于提供额外的元数据信息,以便于开发者在编写程序时进行更高级别的控制和逻辑判断。
使用 @interface 自定义注解时,自动继承了 java.lang.annotation.Annotation 接口。
Java 自定义注解的语法格式如下:
public @interface MyAnnotation {
//定义注解元素
}
其中,@interface
表示定义一个注解,MyAnnotation
是注解名称,可以根据实际需要进行命名,注解元素则是注解的属性,可以指定默认值和约束条件。
使用自定义注解的步骤如下:
- 定义自定义注解;
- 在需要使用注解的地方使用注解;
- 通过反射机制获取注解的属性值,进行相应的操作。
注意:
- 其中的每一个方法实际上是声明了一个配置参数;
- 方法的名称就是参数的名称;
- 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
- 可以通过 default 来声明参数的默认值。
- 如果只有一个参数成员,一般参数名为 value
- 注解元素必须要有值。我们定义注解元素时,经常使用空字符串,0 作为默认值。
这里我们给出一个简单的示例:
public class annotationTest {
//注解可以显示赋值,如果没有默认值,我们就必须给注解复制;
@MyAnnotation(stuID = 03207076,name = "HB")
public void Test() {}
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
//注解的参数:参数类型 + 参数名();
String name() default "";
int stuID();
}
下面再给出一个 Java 自定义注解的示例,它可以用来标记一个类是否是一个单例类:
首先定义一个注解类型:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Singleton {
}
这个注解类型被命名为 Singleton,它可以应用于类上,并且在运行时保留注解信息。
然后在一个类中使用这个注解:
@Singleton
public class MyClass {
// 方法体
}
这个注解将会指示程序这个类是一个单例类。
Java 自定义注解的应用场景有很多,比如在 Spring 框架中,就广泛应用了自定义注解,用于实现依赖注入、AOP 编程等功能。