在 Java 里,有不少内置注解,其中 @Override
、@Deprecated
和 @SuppressWarnings
是较为常见的三个,下面为你详细介绍:
@Override
class Animal {
public void makeSound() {
System.out.println("Some generic sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
Dog
类继承自 Animal
类,Dog
类中的 makeSound
方法使用 @Override
注解表明它重写了父类的 makeSound
方法。如果不小心写错了方法名或者方法签名,编译器会立即报错。@Deprecated
@Deprecated
注解标记的元素时,编译器会给出警告。(只是会给出警告,但是仍然可以调用)package Annotation;
class OldUtils {
@Deprecated
public static void oldMethod() {
System.out.println("This is an old method.");
}
public static void newMethod() {
System.out.println("This is the new and recommended method.");
}
}
public class deprecated {
public static void main(String[] args) {
// 调用已过时的方法,编译器会给出警告
OldUtils.oldMethod();
OldUtils.newMethod();
}
}
OldUtils
类中的 oldMethod
方法被标记为过时,在 Main
类的 main
方法中调用该方法时,编译器会发出警告,提示开发者该方法已不建议使用,应考虑使用 newMethod
。@SuppressWarnings
import java.util.ArrayList;
import java.util.List;
public class SuppressWarningsExample {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
List list = new ArrayList();
list.add("Hello");
// 这里没有进行泛型检查,会产生警告,但使用 @SuppressWarnings 抑制了该警告
}
}
main
方法使用了 @SuppressWarnings("unchecked")
注解,抑制了因未使用泛型而产生的编译器警告。如果使用@SuppressWarnings("all")
那么会抑制所有类型的编译器警告。元注解是用于定义注解的注解,在 Java 中,常见的四种元注解分别是 @Retention
、@Target
、@Documented
和 @Inherited
,下面为你详细介绍:
@Retention
value
属性,该属性的取值为 RetentionPolicy
枚举类型,包含三个值。RetentionPolicy
枚举值
SOURCE
:注解仅保留在源文件中,编译时会被编译器丢弃,不会包含在编译后的字节码文件中。常用于一些编译时检查,如 @Override
注解就使用了该保留策略。CLASS
:注解会保留在编译后的字节码文件中,但在运行时 JVM 不会保留这些注解信息,这是注解的默认保留策略。RUNTIME
:注解不仅会保留在编译后的字节码文件中,而且在运行时 JVM 也会保留这些注解信息,这样就可以通过反射机制在运行时获取注解信息。常用于需要在运行时根据注解进行动态处理的场景。RUNTIME
>CLASS
>SOURCE
**import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// 表示@MyRuntimeAnnotation这个注解在运行整个过程都有效
@Retention(RetentionPolicy.RUNTIME)
@interface MyRuntimeAnnotation {
}
// 表示@MyClassAnnotation这个注解在源文件和编译后的class文件中都有效
@Retention(RetentionPolicy.CLASS)
@interface MyClassAnnotation {
}
//表示@MySourceAnnotation这个注解只在源文件中有效
@Retention(RetentionPolicy.SOURCE)
@interface MySourceAnnotation {
}
@Target
value
属性,该属性的取值为 ElementType
枚举类型,包含多个值。ElementType
常见枚举值
TYPE
:可以应用于类、接口(包括注解类型)或枚举声明。METHOD
:可以应用于方法声明。FIELD
:可以应用于字段声明(包括枚举常量)。PARAMETER
:可以应用于方法的参数声明。CONSTRUCTOR
:可以应用于构造函数声明。import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
// 表示@MethodAnnotation这个注解只能作用于方法
@Target(ElementType.METHOD)
@interface MethodAnnotation {
}
// 表示@FieldAnnotation这个注解只能作用于字段
@Target(ElementType.FIELD)
@interface FieldAnnotation {
}
// Target可以是一个枚举数组,下面就是个例子
// 表示@TypeAndConstructorAnnotation可以作用于类、构造函数声明
@Target({ElementType.TYPE, ElementType.CONSTRUCTOR})
@interface TypeAndConstructorAnnotation {
}
@Documented
javadoc
工具生成文档时,被 @Documented
注解标注的注解会出现在生成的文档中,方便其他开发者了解代码的使用方式。import java.lang.annotation.Documented;
@Documented
@interface MyDocumentedAnnotation {
}
/**
* 使用了 @MyDocumentedAnnotation 注解的类
*/
@MyDocumentedAnnotation
class MyClass {
}
当使用 javadoc
工具生成 MyClass
的文档时,@MyDocumentedAnnotation
注解会显示在文档中。
@Inherited
@Inherited
注解的注解,那么该类的子类也会自动继承这个注解。需要注意的是,@Inherited
只对类有效,对方法和字段等元素无效。import java.lang.annotation.Inherited;
@Inherited
@interface MyInheritedAnnotation {
}
@MyInheritedAnnotation
class ParentClass {
}
class ChildClass extends ParentClass {
}
在上述代码中,ChildClass
继承自 ParentClass
,由于 @MyInheritedAnnotation
注解使用了 @Inherited
元注解,所以 ChildClass
也相当于使用了 @MyInheritedAnnotation
注解。可以通过反射来验证这一点(后面讲,现在了解一下就行):
import java.lang.annotation.Annotation;
public class Main {
public static void main(String[] args) {
Annotation[] annotations = ChildClass.class.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.annotationType().getName());
}
}
}
上述代码运行后,会输出 MyInheritedAnnotation
的全限定名。
在 Java 中,自定义注解可以让开发者根据特定的业务需求为代码添加额外的元数据信息,这些信息可以在编译时、运行时被读取和处理。下面将从自定义注解的定义、使用、与反射结合等方面进行详细介绍。
自定义注解使用 @interface
关键字来定义,同时可以使用元注解(如 @Retention
、@Target
等)来指定注解的保留策略和应用目标。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 定义一个自定义注解
@Retention(RetentionPolicy.RUNTIME) // 指定注解的保留策略为运行时
@Target({ElementType.TYPE, ElementType.METHOD}) // 指定注解可以应用于类和方法
@interface MyCustomAnnotation {
// 定义注解的属性
String value() default ""; // 定义一个名为 value 的属性,默认值为空字符串
int count() default 1; // 定义一个名为 count 的属性,默认值为 1
}
@Retention(RetentionPolicy.RUNTIME)
:指定该注解在运行时仍然保留,这样就可以通过反射机制在运行时获取注解信息。@Target({ElementType.TYPE, ElementType.METHOD})
:指定该注解可以应用于类(ElementType.TYPE
)和方法(ElementType.METHOD
)。String value() default "";
:定义了一个名为 value
的属性,类型为 String
,默认值为空字符串。int count() default 1;
:定义了一个名为 count
的属性,类型为 int
,默认值为 1。属性名=
,而可以直接只传值。属性名=赋的值
。定义好注解后,就可以在代码中使用它。
// 使用自定义注解
@MyCustomAnnotation(value = "This is a class annotation", count = 3)
class MyClass {
@MyCustomAnnotation("This is a method annotation")
public void myMethod() {
System.out.println("This is my method.");
}
}
MyClass
类上使用了 @MyCustomAnnotation
注解,并为 value
和 count
属性指定了值。(这里的赋值规则一定要记住)myMethod
方法上也使用了 @MyCustomAnnotation
注解,由于 value
是注解的默认属性,当只设置 value
属性时,可以省略属性名,但是要设置count
属性时就要指明count = 3。(这就是为什么如果注解只有一个属性,都命名为value)