Java 注解
上次修改时间:2024 年 7 月 4 日
在本文中,我们讨论 Java 注解。
注解是一种特殊的代码元素,它提供关于程序的附加信息。 它们使用 @ 符号附加到类、方法、字段和其他程序元素。
注解本身并不直接影响代码的运行方式,而是提供可供各种工具使用的元数据
- 编译器:编译器可以使用注解来检查错误或在编译期间抑制警告。 例如,@Override 注解告诉编译器验证方法是否确实覆盖了超类中的方法。
- 处理工具:注解可以在编译或部署期间由各种工具处理。 这些工具可以使用注解中的信息来生成代码、配置文件或执行其他任务。 例如,框架可能会使用注解来配置类如何映射到数据库表。
- 运行时:一些注解可在运行时使用反射进行内省。 这允许程序检查类和方法上的注解并采取相应的措施。
- 它们是元数据:注解提供关于程序的补充信息,而不是核心功能。
- 自定义与预定义:您可以定义自己的注解,也可以使用作为 Java 平台或第三方库一部分的预定义注解。
- 作用域:注解可以应用于各种程序元素,如类、方法、字段等。
- 保留策略:注解可以有不同的生命周期。 有些仅在编译期间保留,而另一些则可以通过反射在运行时使用。
@Override 注解
Java 中的 @Override 注解专门用于继承中的方法重写。 它是一个标记注解,用于提高代码清晰度并在编译期间捕获错误。
@Override 的作用- 表明意图:通过将
@Override放置在子类中的方法声明之前,您明确告诉编译器您打算覆盖超类中的方法。 - 编译器检查:编译器验证带有
@Override注解的方法是否确实覆盖了直接超类中具有相同名称、参数列表和返回类型的方法。 如果不是,则会抛出编译错误。 这有助于防止方法名称中的错别字或意外重载(具有相同名称但参数列表不同的方法)等错误。 - 提高可读性:使用
@Override可以突出显示旨在覆盖父类功能的的方法,从而使您的代码更清晰。
@Override 对于重写方法不是强制性的。 编译器通常可以根据签名判断一个方法是否打算覆盖。 但是,为了更好的代码清晰度和及早发现潜在错误,通常认为使用 @Override 是一种好的做法。
@Override 不用于实现接口中的方法。 接口只声明方法,实现接口的子类必须提供自己的实现。 编译器本质上会检查这种关系。
class User {
private final String firstName;
private final String lastName;
private final String occupation;
public User(String firstName, String lastName, String occupation) {
this.firstName = firstName;
this.lastName = lastName;
this.occupation = occupation;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getOccupation() {
return occupation;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("User{");
sb.append("firstName='").append(firstName).append('\'');
sb.append(", lastName='").append(lastName).append('\'');
sb.append(", occupation='").append(occupation).append('\'');
sb.append('}');
return sb.toString();
}
}
void main() {
User[] users = {
new User("John", "Doe", "gardener"),
new User("Roger", "Roe", "driver"),
new User("Paul", "Smith", "teacher"),
};
for (User user : users) {
System.out.println(user);
}
}
在示例中,我们重写了 Object 的 toString 方法。 该方法用 @Override 注释。 如果该函数与父函数不匹配(例如,我们使用 private 而不是 public),我们会收到警告:无法降低从 Object 继承的方法的可见性。
@Deprecated 注解
Java 中的 @Deprecated 注解用于标记不再推荐使用的类、方法、字段或构造函数。 它可以作为对开发人员的警告,他们应该避免使用这些元素并考虑替代方案。
@Deprecated 注解的关键特性
- 信号意图:通过使用
@Deprecated注释一个程序元素,您可以表明不鼓励在新代码中使用它。 可能有更好的替代方案可用,或者该元素可能计划在未来版本中删除。 - 编译器警告:当编译器遇到标记为
@Deprecated的代码元素时,它会生成一条警告消息。 这有助于开发人员识别潜在问题,并鼓励他们迁移到建议的替代方案。 - 重构:
@Deprecated注解通常在 API 的演化过程中使用。 随着库和框架的成熟,某些功能可能会过时或被更有效的方法取代。 弃用允许逐步过渡,而不会破坏依赖旧元素的现有代码。
@Deprecated 注解的其他特性(Java 9 及更高版本)
- since(可选):指定元素被弃用的版本。 这为开发人员提供了关于弃用历史的上下文。
- forRemoval(可选):指示该元素计划在未来的主要版本中删除。 这种更强的警告鼓励开发人员尽快找到替代方案。
class PassWordGenerator {
@Deprecated
public String generatePassword() {
return "generated password";
}
public String generateSecurePassword() {
return "a secure password";
}
}
// @SuppressWarnings("deprecation")
void main() {
var pgen = new PassWordGenerator();
System.out.println(pgen.generateSecurePassword());
System.out.println(pgen.generatePassword());
}
在示例中,我们用 @Deprecated 注释标记 generatePassword,因为它将被更安全的替代方案取代。
可以使用 @SuppressWarnings("deprecation") 注解来抑制 @Deprecated 注解。
自定义注解
我们可以在 Java 中创建自己的注解。 下表总结了自定义 Java 注解的关键要素
| 元素 | 描述 |
|---|---|
| @interface | 创建自定义注解的声明。 |
| @Target | 指定注解可以应用的位置(字段、类、方法等)。 |
| @Retention | 确定注解信息保留的时间(编译时或运行时)。 |
| 元素(方法) | 定义注解的属性或参数(带有数据类型和默认值)。 |
| 文档注释 | 用于记录注解及其用法的可选注释。 |
下一个示例创建一个自定义注解。
package com.zetcode;
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)
public @interface ClassDescription {
String description();
}
我们有一个 ClassDescription,它以类为目标。
package com.zetcode;
import java.util.List;
import java.util.Optional;
public class AnnotationProcessor {
public void process(List<Object> objects) {
objects.forEach(obj -> {
Class<?> clazz = obj.getClass();
ClassDescription annotation = clazz.getAnnotation(ClassDescription.class);
// if (annotation != null) {
// System.out.println(annotation.annotationType().getName());
// System.out.println(annotation.description());
// }
Optional.ofNullable(annotation)
.ifPresentOrElse(
ann -> {
System.out.println(ann.annotationType().getName());
System.out.println(ann.description());
},
() -> System.out.println("No annotation found")
);
});
}
}
AnnotationProcessor 将处理注解。
package com.zetcode;
import java.util.List;
@ClassDescription(description = "this is a User class")
class User {
}
@ClassDescription(description = "this is a Test class")
class Test {
}
class Hello {
}
public class CustomAnnotation {
private String field;
public static void main(String[] args) {
List<Object> objects = List.of(new User(), new Test(), new Hello());
var processor = new AnnotationProcessor();
processor.process(objects);
}
}
我们有两个类用 @ClassDescription 装饰。 我们使用 AnnotationProcessor 处理实例对象,它将打印装饰类的描述。
来源
在本文中,我们介绍了 Java 中的注解。 我们展示了如何使用现有注解以及如何创建一个自定义注解。
作者
列出所有Java教程。