前言:
咱们书接上回,上次按照框架讲了
第一篇,我们讲到了:
①注解的引入(简单概述):在jdk5.0的时候
②注解与注释的区别:
并通过 比喻(日记和标签,贴纸)和 举代码例子 的方式帮助大家更直观的了解二者的区别
③注解的重要性:
并通过 传统方式(XML配置)和 现代方式(使用注解)代码比对的方式,带大家更直观的明白注解的好处
第二篇,我们讲到了:
一,常见的Annotation 作用:(三大作用)
小编给大家总结了很多常见的注解,并且通过具体的代码例子,体会注解在其中发挥的作用以及该如何正确使用
Servlet类(因为咱们主要是讲Java,而这个涉及到HTML了)
开始之前,大家可不可以给小编一个免费的赞或者关注(我们一起进步啊!!!)
@Retention、@Target、@Documented 和 @Inherited,它们允许开发者指定自定义注解的相关特性,例如注解的作用范围、生命周期以及是否会被编译到文档中等。你正在给一幅画做标记,比如说用红圈标出重要的部分,用蓝箭头指出需要特别注意的地方。这些标记帮助别人更好地理解这幅画。在编程中,我们也有类似的东西叫“注解”,它就像是给代码加上一些特殊的标记,告诉计算机或者其他程序员这段代码有什么特殊的意义或者应该怎么处理。
元注解就是给这些“标记”本身再加一个标记。就好比你在红圈旁边写上“这个红圈意味着重要信息”,或者在蓝箭头旁边说明“这个箭头指向需要注意的区域”。元注解就是用来解释我们创建的那些注解是什么意思,或者应该怎样使用。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyCustomAnnotation {
String value();
}
创建一个名为 @NeedsTesting 的注解,当你在某个方法上使用这个注解时,就表示这个方法需要被测试。为了确保这个注解能在运行时被读取,并且只能应用于方法上,
// 告诉Java这个注解应该在运行时还能被读取
@Retention(RetentionPolicy.RUNTIME)
// 指定这个注解只能用在方法上
@Target(ElementType.METHOD)
public @interface NeedsTesting {
// 这个注解还可以带一个参数,比如测试的优先级
int priority() default 1;
}
public class MyClass {
@NeedsTesting(priority = 5) // 标记这个方法需要高优先级的测试
public void myMethod() {
// 方法的实现
}
}
可以通过 枚举类型 ElementType 的10个常量对象来指定 :
举个栗子:
创建一个名为 @Author 的注解,我们希望它只能用在类和方法上。我们可以这样定义:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 指定 @Author 注解只能用于类和方法
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME) // 表示该注解将在运行时保留
public @interface Author {
String name(); // 作者的名字
String date() default "2024-12-26"; // 默认日期
}
在我们的代码中像这样使用 @Author 注解:
// 正确使用:应用于类
@Author(name = "张三")
public class MyClass {
// 正确使用:应用于方法
@Author(name = "李四", date = "2024-12-25")
public void myMethod() {
// 方法的实现
}
// 错误使用:尝试应用于字段(根据 @Target 定义,这是不允许的)
// @Author(name = "王五") // 这行代码会导致编译错误
private String myField;
}
代码解释和总结:
你写了一封信(注解),然后你决定这封信可以在什么情况下被读到:
RetentionPolicy 的常量对象:
RetentionPolicy 枚举类型定义了3个常量,它们分别代表不同的生命周期:
创建一个名为 @DebugInfo 的注解,我们希望它能够在运行时被读取,以便于调试工具可以获取这些信息。我们可以这样定义:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 指定 @DebugInfo 注解将在运行时保留
@Retention(RetentionPolicy.RUNTIME)
// 指定 @DebugInfo 注解只能用于方法
@Target(ElementType.METHOD)
public @interface DebugInfo {
String value(); // 调试信息
}
我们可以在我们的代码中像这样使用 @DebugInfo 注解:
public class MyClass {
// 使用 @DebugInfo 注解添加调试信息
@DebugInfo("This method adds two numbers.")
public int add(int a, int b) {
return a + b;
}
// 一个简单的测试方法,用来读取并打印 @DebugInfo 注解的信息
public static void main(String[] args) throws Exception {
// 获取 MyClass 类的所有方法
for (java.lang.reflect.Method method : MyClass.class.getDeclaredMethods()) {
// 检查方法上是否有 @DebugInfo 注解
if (method.isAnnotationPresent(DebugInfo.class)) {
// 获取并打印 @DebugInfo 注解的值
DebugInfo debugInfo = method.getAnnotation(DebugInfo.class);
System.out.println("Debug Info for " + method.getName() + ": " + debugInfo.value());
}
}
}
}
代码解释和总结:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 指定 @DeprecatedMethod 注解应该被 javadoc 工具记录
@Documented
// 指定 @DeprecatedMethod 注解将在运行时保留
@Retention(RetentionPolicy.RUNTIME)
// 指定 @DeprecatedMethod 注解只能用于方法
@Target(ElementType.METHOD)
public @interface DeprecatedMethod {
String reason() default "未提供原因"; // 废弃的原因
}
/**
* 一个示例类,包含一些方法。
*/
public class MyClass {
/**
* 一个已经被废弃的方法,不建议使用。
*
* @deprecated 请使用 {@link #newMethod} 代替。
*/
@DeprecatedMethod(reason = "该方法已被新方法取代")
public void oldMethod() {
System.out.println("这是一个旧方法。");
}
/**
* 新的方法,推荐使用。
*/
public void newMethod() {
System.out.println("这是一个新方法。");
}
}
代码解释和总结:
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// 指定 @Versioned 注解可以被子类继承
@Inherited
// 指定 @Versioned 注解将在运行时保留
@Retention(RetentionPolicy.RUNTIME)
// 指定 @Versioned 注解只能用于类
@Target(ElementType.TYPE)
public @interface Versioned {
String version(); // 版本号
}
在我们的代码中像这样使用 @Versioned 注解:
// 父类带有 @Versioned 注解
@Versioned(version = "1.0")
public class ParentClass {
public void display() {
System.out.println("这是父类的方法。");
}
}
// 子类没有显式地添加 @Versioned 注解,但会自动继承父类的注解
public class ChildClass extends ParentClass {
@Override
public void display() {
System.out.println("这是子类的方法。");
}
}
// 一个简单的测试方法,用来读取并打印 @Versioned 注解的信息
public class TestInheritance {
public static void main(String[] args) {
// 获取 ParentClass 类的 @Versioned 注解
Versioned parentVersion = ParentClass.class.getAnnotation(Versioned.class);
if (parentVersion != null) {
System.out.println("ParentClass version: " + parentVersion.version());
}
// 获取 ChildClass 类的 @Versioned 注解
Versioned childVersion = ChildClass.class.getAnnotation(Versioned.class);
if (childVersion != null) {
System.out.println("ChildClass version: " + childVersion.version());
} else {
System.out.println("ChildClass did not inherit the @Versioned annotation.");
}
}
}
【元注解】
【修饰符】 @interface 注解名{
【成员列表】
}
定义自定义注解:
import java.lang.annotation.*;
// 定义 TaskPriority 枚举,用于表示任务的优先级
public enum TaskPriority {
LOW, MEDIUM, HIGH
}
// 定义 @TaskInfo 注解
@Documented // 表明这个注解应该被 javadoc 工具记录
@Inherited // 允许子类继承父类中的注解
@Target(ElementType.TYPE) // 指定注解只能用于类
@Retention(RetentionPolicy.RUNTIME) // 指定注解将在运行时保留
public @interface TaskInfo {
// 配置参数:任务名称,默认值为 "Unnamed Task"
String name() default "Unnamed Task";
// 配置参数:任务优先级,默认值为 TaskPriority.LOW
TaskPriority priority() default TaskPriority.LOW;
// 配置参数:任务截止日期,默认值为空字符串
String deadline() default "";
// 配置参数:任务描述,默认值为空字符串
String description() default "";
}
使用自定义注解:
// 父类带有 @TaskInfo 注解
@TaskInfo(
name = "Develop Feature A",
priority = TaskPriority.HIGH,
deadline = "2024-12-31",
description = "Implement the core functionality of the application."
)
public class ParentTask {
public void execute() {
System.out.println("Executing ParentTask.");
}
}
// 子类没有显式地添加 @TaskInfo 注解,但会自动继承父类的注解
public class ChildTask extends ParentTask {
@Override
public void execute() {
System.out.println("Executing ChildTask.");
}
}
// 测试类,用来读取并打印 @TaskInfo 注解的信息
public class TestTaskInfo {
public static void main(String[] args) {
// 获取 ParentTask 类的 @TaskInfo 注解
TaskInfo parentTaskInfo = ParentTask.class.getAnnotation(TaskInfo.class);
if (parentTaskInfo != null) {
printTaskInfo(parentTaskInfo, "ParentTask");
}
// 获取 ChildTask 类的 @TaskInfo 注解
TaskInfo childTaskInfo = ChildTask.class.getAnnotation(TaskInfo.class);
if (childTaskInfo != null) {
printTaskInfo(childTaskInfo, "ChildTask");
} else {
System.out.println("ChildTask did not inherit the @TaskInfo annotation.");
}
}
// 辅助方法,用来打印 TaskInfo 注解的信息
private static void printTaskInfo(TaskInfo taskInfo, String className) {
System.out.println(className + " info:");
System.out.println(" Name: " + taskInfo.name());
System.out.println(" Priority: " + taskInfo.priority());
System.out.println(" Deadline: " + taskInfo.deadline());
System.out.println(" Description: " + taskInfo.description());
}
}
你正在管理一个项目,每个任务都有名字、优先级、截止日期和描述。为了帮助团队成员更好地理解每个任务,你决定在代码中为每个任务添加一些标签(注解)。这些标签可以帮助你在编写代码时记住任务的详细信息,并且可以在生成文档时自动包含这些信息。
1. 定义自定义注解
创建一个名为 @TaskInfo 的注解,用来标记任务的相关信息。这个注解将包含任务的名称、优先级(枚举类型)、截止日期(字符串),并且可以在运行时被读取和处理。
import java.lang.annotation.*;
// 定义 TaskPriority 枚举,用于表示任务的优先级
public enum TaskPriority {
LOW, MEDIUM, HIGH
}
// 定义 @TaskInfo 注解
@Retention(RetentionPolicy.RUNTIME) // 指定注解将在运行时保留
@Target(ElementType.TYPE) // 指定注解只能用于类
public @interface TaskInfo {
String name() default "Unnamed Task"; // 任务名称,默认值为 "Unnamed Task"
TaskPriority priority() default TaskPriority.LOW; // 任务优先级,默认值为 LOW
String deadline() default ""; // 任务截止日期,默认值为空字符串
String description() default ""; // 任务描述,默认值为空字符串
}
2. 使用自定义注解
在一个类中使用 @TaskInfo 注解,
// 使用 @TaskInfo 注解标记一个任务
@TaskInfo(
name = "Develop Feature A",
priority = TaskPriority.HIGH,
deadline = "2024-12-31",
description = "Implement the core functionality of the application."
)
public class TaskA {
public void execute() {
System.out.println("Executing TaskA.");
}
}
// 另一个任务,没有显式地添加 @TaskInfo 注解
public class TaskB {
public void execute() {
System.out.println("Executing TaskB.");
}
}
3. 读取和处理自定义注解
为了读取和处理这些注解,我们需要使用 Java 的反射 API 来获取注解信息并根据需要进行处理。可以创建一个工具类 TaskManager 来管理任务。
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
public class TaskManager {
// 辅助方法,用来打印 TaskInfo 注解的信息
private static void printTaskInfo(TaskInfo taskInfo, String className) {
System.out.println(className + " info:");
System.out.println(" Name: " + taskInfo.name());
System.out.println(" Priority: " + taskInfo.priority());
System.out.println(" Deadline: " + taskInfo.deadline());
System.out.println(" Description: " + taskInfo.description());
}
// 方法:读取并处理所有带有 @TaskInfo 注解的任务
public static void processTasks(List<Class<?>> taskClasses) {
for (Class<?> taskClass : taskClasses) {
// 检查类上是否有 @TaskInfo 注解
if (taskClass.isAnnotationPresent(TaskInfo.class)) {
TaskInfo taskInfo = taskClass.getAnnotation(TaskInfo.class);
printTaskInfo(taskInfo, taskClass.getSimpleName());
// 创建任务实例并执行
try {
Object taskInstance = taskClass.getDeclaredConstructor().newInstance();
if (taskInstance instanceof Task) {
((Task) taskInstance).execute();
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.out.println(taskClass.getSimpleName() + " does not have @TaskInfo annotation.");
}
}
}
// 接口:定义任务必须实现的方法
public interface Task {
void execute();
}
}
4. 测试注解的读取和处理
最后,我们编写一个测试类 TestTaskManager,来验证 TaskManager 是否能正确读取和处理带有 @TaskInfo 注解的任务。
public class TestTaskManager {
public static void main(String[] args) {
// 创建一个任务列表,包含 TaskA 和 TaskB
List<Class<?>> tasks = new ArrayList<>();
tasks.add(TaskA.class);
tasks.add(TaskB.class);
// 调用 TaskManager 处理任务
TaskManager.processTasks(tasks);
}
}
大白话拆解:
ok,我们注解也彻底完结了。希望对大家有帮助。
键盘敲烂,月薪过万!!!
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- 91gzw.com 版权所有 湘ICP备2023023988号-2
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务