Java 注解(Annotation)是 JDK 5.0 引入的一种元数据机制,用于描述某些代码的附加信息,这些信息可以在运行时或编译时被读取。注解本身不会改变程序的执行流程,但可以被编译器或运行时环境用来进行额外的处理。
注解的定义
Java 注解使用 @interface
关键字来定义,例如:
public @interface TestInterface {
String value() default "默认注解";
}
注解的应用
注解可以应用于类、方法、成员变量、参数、构造器和包等元素上,为这些元素附加某种元数据。
@TestInterface("这是一个注解示例")
public class Test {
//.....
}
内置注解
Java 提供了几个内置注解,如 @Override
、@Deprecated
和 @SuppressWarnings
。
@Override
:表示一个方法是重写了父类或是实现了接口中的一个方法。@Deprecated
:表示某个类或方法已经过时,不建议使用。@SuppressWarnings
:告诉编译器忽略特定的警告信息。
元注解
元注解是用于描述注解的注解,Java 定义了 4 个标准的 meta-annotation 类型,它们被用来提供对其它 annotation 类型作注解。这些类型和它们所支持的类在 java.lang.annotation 包中可以找到。
@Target
: 表示该注解可以用于什么地方。可能的 ElementType 参数包括:- CONSTRUCTOR: 构造器的声明
- FIELD: 域声明(包括枚举的常量)
- LOCAL_VARIABLE: 局部变量声明
- METHOD: 方法声明
- PACKAGE: 包声明
- PARAMETER: 参数声明
- TYPE: 类、接口(包括注解类型)或枚举的声明
@Retention
: 表示需要在什么级别保存该注解信息,用于描述注解的生命周期(SOURCE < CLASS < RUNTIME)。@Documented
: 将此注解包含在 javadoc 中。@Inherited
: 允许子类继承父类的注解。
自定义注解
你可以根据需要创建自定义注解,并定义注解的元素和默认值等。例如:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@TestInterface //写在在这会报错,因为这个注解限定只能用在方法上
public class Test {
@TestInterface
public String testInterface (){
return "";
}
//.....
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface TestInterface {
String value() default "默认注解";
}
自定义注解的一些特殊使用
特殊语法一:
如果注解本身没有注解类型元素,那么在使用注解的时候可以省略(),直接写为:@注解名,它和标准语法@注解名()等效!
@TestInterface
public class Test {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@interface TestInterface {
}
特殊语法二:
如果注解本本身只有一个注解类型元素,而且命名为value,那么在使用注解的时候可以直接使用:@注解名(注解值),其等效于:@注解名(value = 注解值)。
@TestInterface(name = "这个一个注解")
public class Test {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@interface TestInterface {
String[] name();
}
特殊用法三:
如果注解中的某个注解类型元素是一个数组类型,在使用时又出现只需要填入一个值的情况,那么在使用注解时可以直接写为:@注解名(类型名 = 类型值),它和标准写法:@注解名(类型名 = {类型值})等效!
@TestInterface(name = "这个一个注解")
public class Test {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@interface TestInterface {
String[] name();
}
@TestInterface(name = {"第一个值","第二个值"})
class TestArrayInterface {
}
特殊用法四:
如果一个注解的@Target是定义为Element.PACKAGE,那么这个注解是配置在package-info.java中的,而不能直接在某个类的package代码上面配置。
注:package-info.java 提供包级别的类(或接口),这些类(或接口)只有本包里才能访问,即使是子包也不能访
自定义注解的使用例子:
/**
* @author: Admin
* @Desc: 测试自定注解类
* @create: 2024-08-02 16:54
**/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.TYPE})
public @interface TestInterface {
String name() default "默认值";
int age() default 18;
String hobbies() default "篮球";
String address() default "北京";
}
/**
* @author: Admin
* @Desc: 测试自定注解类实体类
* @Date: 2024/8/5 14:14
*/
public class Person {
String name;
int age;
String address;
String hobbies;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getHobbies() {
return hobbies;
}
public void setHobbies(String hobbies) {
this.hobbies = hobbies;
}
}
/**
* @author: Admin
* @Desc: 测试自定注解类业务类
* @Date: 2024/8/5 14:14
*/
public class TestService {
@TestInterface(name = "张三", age = 22, address = "广州", hobbies = "足球")
public void writeInfo(Person person) {
String info = String.format("姓名:%s,年龄:%d,地址:%s,爱好:%s", person.getName(), person.getAge(), person.getAddress(), person.getHobbies());
System.out.println(info);
}
}
/**
* @author: Admin
* @Desc: 测试类
* @create: 2024-08-02 16:54
**/
public class Test {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = TestService.class;
Method method = clazz.getMethod("writeInfo",Person.class);
if (!method.isAnnotationPresent(TestInterface.class)) {
System.out.printf("没有注解");
return;
}
TestInterface info = method.getAnnotation(TestInterface.class);
Person person = new Person();
person.setName(info.name());
person.setAge(info.age());
person.setAddress(info.address());
person.setHobbies(Arrays.asList(info.hobbies()).toString());
TestService testService = new TestService();
method.invoke(testService, person);
}
}
执行结果:
姓名:张三,年龄:22,地址:广州,爱好:[足球]
注解的使用场景
1.编译时注解:
代码生成:注解可以用于生成额外的代码,例如,通过Lombok库自动生成getter和setter方法。
配置IDE:注解可以提供IDE特定的信息,如重构、代码分析等。
2.运行时注解:
依赖注入:在Spring框架中,注解如@Autowired用于自动装配依赖项。
数据验证:使用JSR 380(Bean Validation 2.0)注解,如@NotNull和@Size在运行时验证对象状态。
3.设计时注解:
API文档:如Javadoc注解,用于生成API文档。
框架配置:许多框架使用注解来配置框架行为,如Spring的@Controller、@Service等。
4.测试注解:
测试框架:JUnit等测试框架使用注解如@Test、@Before、@After来标记测试方法和测试生命周期方法。
5.序列化与反序列化:
JSON处理:Jackson和Gson等库使用注解来控制JSON的序列化和反序列化行为。
6.事务管理:
声明式事务:在Spring框架中,使用@Transactional注解来声明事务的边界和行为。
7.安全性:
权限控制:Spring Security等安全框架使用注解如@Secured、@RolesAllowed来控制访问权限。
8.性能监控:
方法执行时间:使用注解来标记需要监控的方法,然后通过特定的工具来测量其执行时间。
9.模块化和插件系统:
扩展点:框架或应用程序可以定义注解作为扩展点,允许第三方模块通过注解来注册它们的组件。
10.构建工具配置:
Maven和Gradle:这些构建工具使用注解来定义项目的配置和依赖关系。
11.RESTful Web服务:
路由和控制器:在使用Spring MVC或JAX-RS等框架时,注解用于定义路由和控制器方法。
12.数据库访问:
ORM框架:Hibernate和MyBatis等ORM框架使用注解来映射Java类到数据库表。
13.自定义注解:
特定业务逻辑:开发者可以创建自定义注解来标记特定的业务逻辑或代码段,然后在运行时通过反射进行处理。