【java】注解

注解

什么是注解

  • Annotation(注解)是从JDK5.0开始引入的新技术。
  • Annotation的作用:
    • 不是程序本身必需的,但是可以对程序做出解释。
    • 可以被其他程序(比如编译器等)读取。
  • Annotation的格式:
    • 注解是以“@注释名”在代码中存在的,还可以添加一些参数值,例如:@SuppressWarnings(value=“unchecked”)。
  • Annotation在哪里可以使用?
    • 可以附加在package,class,method,field等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问。

注解的分类

内置注解

在 Java 里,有不少内置注解,其中 @Override@Deprecated@SuppressWarnings 是较为常见的三个,下面为你详细介绍:

1. @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 方法。如果不小心写错了方法名或者方法签名,编译器会立即报错。
2. @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
3. @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,下面为你详细介绍:

1. @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 {
}
2. @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 {
}
3. @Documented
  • 作用:这是一个标记注解,用于指定被它标注的注解会被包含在 JavaDoc 文档中。当使用 javadoc 工具生成文档时,被 @Documented 注解标注的注解会出现在生成的文档中,方便其他开发者了解代码的使用方式。
示例代码
import java.lang.annotation.Documented;

@Documented
@interface MyDocumentedAnnotation {
}

/**
 * 使用了 @MyDocumentedAnnotation 注解的类
 */
@MyDocumentedAnnotation
class MyClass {
}

当使用 javadoc 工具生成 MyClass 的文档时,@MyDocumentedAnnotation 注解会显示在文档中。

4. @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。
  • 若注解只需要一个属性,那不管是什么类型都叫做value,这样做的好处就是在使用注解的时候不需要显式的属性名=,而可以直接只传值。
  • 注解的属性怎么给默认值用default,例如int age() default 18,若注解属性没有默认值,那么在使用注解的时候就一定得给这个属性赋值,否则会报错,赋值时格式一定是属性名=赋的值
自定义注解的使用

定义好注解后,就可以在代码中使用它。

示例代码
// 使用自定义注解
@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 注解,并为 valuecount 属性指定了值。(这里的赋值规则一定要记住)
  • myMethod 方法上也使用了 @MyCustomAnnotation 注解,由于 value 是注解的默认属性,当只设置 value 属性时,可以省略属性名,但是要设置count属性时就要指明count = 3。(这就是为什么如果注解只有一个属性,都命名为value)

你可能感兴趣的:(java,开发语言)