当前位置: 首页 > news >正文

sky-take-out项目中的切点

package com.sky.annotation;import com.sky.enumeration.OperationType;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 AutoFill {
//    数据库操作类型OperationType value();
}

在使用这个注解时: @AutoFill(OperationType.INSERT)
为什么写在这里的 OperationType.INSERT 就是返回结果?

这是一个非常典型、但又容易让人困惑的 Java 注解语法问题。下面从Java 注解的定义到使用方式,彻底讲清楚为什么 OperationType.INSERT 会被当作注解的值返回。


🧠 一、背景回顾

定义了一个自定义注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {OperationType value();
}

这个注解只有一个抽象方法:OperationType value();,表示你需要传入一个 OperationType 类型的值。

然后你在某个方法上使用它:

@AutoFill(OperationType.INSERT)
void insert(Employee employee);

为什么这里写的是 OperationType.INSERT,却相当于“返回”了这个值?


🔍 二、Java 注解的特殊语法机制

在 Java 中,当你使用一个注解时,如果该注解有成员变量(即定义时的方法),你可以通过以下方式传递参数:

@AutoFill(value = OperationType.INSERT)

或者简写为:

@AutoFill(OperationType.INSERT)

✅ 规则:

  • 如果注解中只有一个成员变量,并且名字叫 value()
  • 那么在使用注解时可以省略 value =,直接写值。

这就是为什么你可以写成:

@AutoFill(OperationType.INSERT)

而不是必须写成:

@AutoFill(value = OperationType.INSERT)

💡 三、没有 return,那值是怎么来的?

这是关键点!

1. 注解的本质是一个接口

你定义的:

public @interface AutoFill {OperationType value();
}

其实等价于一个接口:

public interface AutoFill extends java.lang.annotation.Annotation {OperationType value();
}

2. Java 运行时会生成注解代理对象

当你这样写:

@AutoFill(OperationType.INSERT)

Java 编译器和运行时系统会为你自动创建一个实现了 AutoFill 接口的代理类实例,并在这个实例中实现 value() 方法,返回你写的那个值:

class AutoFillImpl implements AutoFill {public OperationType value() {return OperationType.INSERT; // ← 这个就是你写的值}
}

所以你通过反射获取到的 AutoFill 对象:

AutoFill autoFill = method.getAnnotation(AutoFill.class);
OperationType operationType = autoFill.value(); // ← 得到的就是 INSERT

这里的 .value() 实际上调用的是 Java 自动生成的那个代理对象的方法,不是你自己写的 return,而是编译器帮你做了这件事。


🧪 四、举个更简单的例子帮助理解

假设你有一个最简单的注解:

public @interface MyAnnotation {String value();
}

然后你使用它:

@MyAnnotation("Hello")
public void myMethod() {}

那么你通过反射拿到注解后:

MyAnnotation ann = method.getAnnotation(MyAnnotation.class);
String value = ann.value(); // "Hello"

你有没有写 return "Hello"?没有。但是 Java 自动帮你做了这件事。


📌 五、总结一句话

@AutoFill(OperationType.INSERT) 中的 OperationType.INSERT 是作为注解的 value() 成员值传入的,Java 在编译和运行时会自动创建一个实现了 AutoFill 接口的代理对象,并让它的 value() 方法返回你传入的值,所以你不需要手动写 return


🧩 六、扩展知识(可选)

概念解释
注解属性默认值可以给注解方法设置默认值:String name() default "default";
多个属性写法如果注解有多个属性,就不能省略名字了:
@MyAnno(name = "Tom", age = 20)
注解只能放常量注解中的值必须是编译时常量,比如基本类型、字符串、枚举、Class 等



为什么我在定义注解的时候要写成 OperationType value(); 而不是 OperationType value;

这是 Java 注解(Annotation)语法中一个非常关键的细节。我们来从 Java 注解的本质、设计原理和语法规范 来彻底解释这个问题。

🧠 一、本质:注解本质上是一个接口

在 Java 中,注解(@interface)并不是普通的类或变量,它本质上是一个特殊的接口

当你这样定义一个注解:

public @interface AutoFill {OperationType value();
}

其实就相当于定义了一个接口:

public interface AutoFill extends java.lang.annotation.Annotation {OperationType value();
}

所以,你写的 OperationType value(); 实际上是这个接口中的一个抽象方法(abstract method),而不是一个字段(field)!


❓二、那为什么不直接写成字段的形式,比如:

public @interface AutoFill {OperationType value; // ❌ 错误写法!Java 不允许这样
}

因为 Java 的注解设计时明确规定了:

注解的“属性”必须通过抽象方法的形式来声明,不能使用字段。

也就是说,在注解中你不能像普通类一样定义变量,而是要用方法签名的方式来表示属性。


🔍 三、为什么设计成方法的形式?

这是 Java 注解系统的设计选择,主要有以下几个原因:

1. 保持与接口一致

既然注解本质是一个接口,那就必须遵循接口的语法结构,接口里只能有方法,不能有字段。

2. 统一访问方式

用方法的形式可以统一访问注解属性的方式。例如无论你在注解中定义了什么属性,都可以通过调用对应的方法获取值:

AutoFill autoFill = method.getAnnotation(AutoFill.class);
OperationType type = autoFill.value(); // ← 通过方法调用获取值

如果允许写成字段形式,就需要一种新的访问机制,破坏语言的一致性。

3. 支持默认值

你可以为注解属性设置默认值,这只能通过方法的形式实现:

public @interface MyAnnotation {String name() default "default";
}

如果是字段,就无法表达“默认值”的概念。


🧪 四、举个例子对比说明

✅ 正确写法(方法形式):

public @interface MyAnnotation {String name();int age() default 18;
}

使用:

@MyAnnotation(name = "Tom")
public void myMethod() {}

反射获取:

MyAnnotation ann = method.getAnnotation(MyAnnotation.class);
System.out.println(ann.name()); // 输出 Tom
System.out.println(ann.age());  // 输出 18(默认值)

❌ 错误写法(字段形式):

public @interface MyAnnotation {String name; // 编译错误!
}

这段代码会报错,Java 不允许注解中出现字段。


✅ 五、总结一句话

在 Java 注解中,你不能定义字段,只能通过抽象方法的形式来声明属性。因此你要写成 OperationType value(); 而不是 OperationType value;,这是 Java 注解语法的规定,也是为了保持接口一致性、统一访问方式和支持默认值等设计目标。


🧩 六、附加知识点

内容解释
@interface 是什么?是 Java 中定义注解的关键字,它继承自 java.lang.annotation.Annotation 接口
注解属性能不能是变量?不行,必须是抽象方法
可以给注解属性设默认值吗?可以,如 String name() default "abc";
注解属性能不能是任意类型?不行,只能是基本类型、String、枚举、Class、数组等编译时常量类型
http://www.dtcms.com/a/283310.html

相关文章:

  • 工控机内Docker容器间Socket通信实现
  • 继电器驱动电路注意的坑
  • AI产品经理面试宝典第30天:AI+教育个性化学习与知识图谱相关面试题的解答指导
  • 解锁支付宝小程序日活增长密码
  • 使用YOLOv11实现水果类别检测:从数据到模型训练的全过程
  • 【IDEA】格式化代码工具配置
  • 【语音技术】影视技能实现方法详细介绍
  • 基于拓扑图的故障定位系统:现代网络与电网的守护者
  • 31.Python 中初始化列表的几种方式
  • JS的防抖与节流
  • Javase总体回顾
  • EP01:【NLP 第二弹】自然语言处理概述
  • Postman接口
  • 代码随想录算法训练营第二十二天
  • AI编程神器 Claude Code 安装及使用体验
  • 横向移动(下)
  • RAG测试用例集的构造(Ragas的用法)
  • cell2location复现
  • MySQL基础学习之DML,DQL(二)
  • 访问继承成员(C++)
  • C语言数据存储与指针
  • 选择亿林数据软件测试服务,为哈尔滨企业数字化转型赋能
  • Rust入门之并发编程基础(三)
  • CSS全面系统教程:从入门到精通网页样式设计
  • Datawhale AI夏令营笔记-TF-IDF方法
  • 深度学习入门-卷积神经网络(CNN)
  • JS修改布局--两列布局,拖拽中间修改左右的宽度
  • GI6E 打破網路封鎖:保護你的通信身份安全
  • AI Agent开发学习系列 - langchain之LCEL(2):LCEL 链式表达解析
  • Java对象的比较