注解基础
注解是JDK1.5版本引入的一个新特性,用于对代码进行说明。
注解的作用
- 通过代码里标识的元数据生成javadoc文档
- 编译检查
- 编译时动态处理,比如说动态生成代码
- 运行时动态处理,比如说使用反射注入实例
注解的分类
- Java自带的标准注解,包括
@Override
、@Deprecated
和@SuppressWarnings
,分别用于标明重写某个方法、标明某个类或方法过时、标明要忽略的警告,用这些注解标明后编译器就会进行检查。 - 元注解,元注解是用于定义注解的注解,包括
@Retention
、@Target
、@Inherited
、@Documented
,@Retention
用于标明注解被保留的阶段,@Target
用于标明注解使用的范围,@Inherited
用于标明注解可继承,@Documented
用于标明是否生成javadoc文档。 - 自定义注解,可以根据自己的需求定义注解,并可用元注解对自定义注解进行注解。
Java内置注解
public class Solution {
public void test(){}
}
class Test extends Solution {
/**
* 重写父类方法
*/
@Override
public void test() {
}
/**
* 被弃用的方法(后续版本可能移除,不推荐再使用)
*/
@Deprecated
public void oldMethod(){
}
/**
* 忽略警告
*/
@SuppressWarnings("rawtypes")
public List list(){
return new ArrayList<>();
}
}
@Override
我们来看一下这个注解的内部是什么样子:
@Target(ElementType.METHOD) // 表示该注解用来修饰方法的
@Retention(RetentionPolicy.SOURCE) // 表示该注解仅在编译时有效
public @interface Override {
}
@Deprecated
@Documented // 能够被文档化
@Retention(RetentionPolicy.RUNTIME) // 可以保留到运行时
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE}) // 作用域相当的广泛
public @interface Deprecated {
/**
* Returns the version in which the annotated element became deprecated.
* The version string is in the same format and namespace as the value of
* the {@code @since} javadoc tag. The default value is the empty
* string.
*
* @return the version string
* @since 9
*/
String since() default "";
/**
* Indicates whether the annotated element is subject to removal in a
* future version. The default value is {@code false}.
*
* @return whether the element is subject to removal
* @since 9
*/
boolean forRemoval() default false;
}
@SuppressWarnings
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE}) // 作用域相当广泛
@Retention(RetentionPolicy.SOURCE) // 仅在编译时有效
public @interface SuppressWarnings {
/**
* The set of warnings that are to be suppressed by the compiler in the
* annotated element. Duplicate names are permitted. The second and
* successive occurrences of a name are ignored. The presence of
* unrecognized warning names is <i>not</i> an error: Compilers must
* ignore any warning names they do not recognize. They are, however,
* free to emit a warning if an annotation contains an unrecognized
* warning name.
*
* <p> The string {@code "unchecked"} is used to suppress
* unchecked warnings. Compiler vendors should document the
* additional warning names they support in conjunction with this
* annotation type. They are encouraged to cooperate to ensure
* that the same names work across multiple compilers.
* @return the set of warnings to be suppressed
*/
String[] value();
}
元注解
@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();
}
该注解的作用就是限定注解的使用范围,具体范围如下:
public enum ElementType {
TYPE, // 类、接口、枚举类
FIELD, // 成员变量(包括:枚举常量)
METHOD, // 成员方法
PARAMETER, // 方法参数
CONSTRUCTOR, // 构造方法
LOCAL_VARIABLE, // 局部变量
ANNOTATION_TYPE, // 注解类
PACKAGE, // 可用于修饰:包
TYPE_PARAMETER, // 类型参数,JDK 1.8 新增
TYPE_USE // 使用类型的任何地方,JDK 1.8 新增
}
我们可以看到该注解自身也加上了一个 @Target(ElementType.ANNOTATION_TYPE) 。
@Retention
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
该注解的作用就是描述注解保留的时间(或者叫做阶段吧)。总共有三个阶段:
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
(英文描述得已经很清晰了)
@Documented
该注解的作用就是在使用 javadoc 工具为类生成帮助文档时保留注解信息。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
@Inherited
如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
注解与反射
在使用SpringBoot进行开发的时候,你会感慨为什么写几个注解就能够将项目跑起来,那肯定是因为框架的开发者在你看不见的地方替你完成了某些操作。
注意:注解的生命周期只有是 RUNTIME 才能通过反射去获取。
自定义注解
我们来编写一个属于自己的注解吧。
package com.kaiven.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 作用在方法上
@Retention(RetentionPolicy.RUNTIME) // 保留到运行时,否则无法通过反射获取
public @interface GetMapping {
String value() default "";
}
package com.kaiven;
import com.kaiven.anno.GetMapping;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws NoSuchMethodException {
Method hello = Main.class.getMethod("hello");
// 如果该方法上有GetMapping注解
if (hello.isAnnotationPresent(GetMapping.class)) {
GetMapping annotation = hello.getAnnotation(GetMapping.class);
System.out.println(annotation.value());
}
}
@GetMapping("/hello")
public String hello(){
return "Hello world!";
}
}
有没有那一点点的味道了?
深入理解注解
注解支持继承嘛?
注解是不支持继承的,但注解在编译之后,编译器会自动继承java.lang.annotation.Annotation接口。
注解实现的原理?
https://blog.csdn.net/qq_20009015/article/details/106038023
(对于注解的应用,大多还是与Spring相关的,最大的一个变化就是从xml配置项目到注解化的转变)
2024.10.26
writeBy kaiven