注解
什么是注解
Java 注解(Annotation)是 JDK 5.0 引入的一种元素,用于为 Java 代码提供元数据。元数据是关于数据的数据,它为代码提供附加信息,而这些信息并不直接参与到程序的逻辑中,但可以被编译器或其他工具使用。注解本身对代码的逻辑没有任何影响,但可以通过反射机制读取注解信息,从而执行相应的操作。
注解的作用
- 不是程序本身,可以对程序作出解释
- 可以被其他程序(如:编译器等)读取。注解可以通过反射对其进行解释处理,这个是注解与注释的最大区别。
如果一个注解没有通过反射进行注解信息处理,那么这个注解毫无意义。
注解的格式
注解是以 “@注释名” 在代码中存在的,还可以添加一下参数值,例如:@SuppressWarnings({“unchecked”, “rawtypes”})
注解的使用范围
注解可以附加在package,class,method,field等上面,相当于给他们添加了额为的辅助信息,我们可以通过反射机制变成实现对这些元素的访问。
注解的分类
Java 注解可以分为以下三种类型:
- 标记注解:没有任何属性的注解,如 @Override。
- 单值注解:只有一个属性的注解,如 @Deprecated(“不建议使用”)。
- 完整注解:包含多个属性的注解,如 @SuppressWarnings({“unchecked”, “rawtypes”})。
Java 的内置注解包括:
- @Override:表示当前方法是重写了父类的方法。
- @Deprecated:表示某个类或方法已经过时,不建议使用。
- @SuppressWarnings:用于告诉编译器忽略指定的警告。
除了内置注解,Java 还允许开发者自定义注解。
如何自定义注解
使用@interface自定义注解是,自动继承了java.lang.annotation.Annotation接口
格式
public @interface 注解名{定义体}
示例:声明一个MyAnnotation注解,包含value(默认值 “”)、number(默认值 0)两个参数
public @interface MyAnnotation {
String value() default "";
int number() default 0;
}
其中的每一个方法实际上是声明了一个配置参数。
- 方法名称就是参数的名称
- 返回值类型就是参数的类型(返回值类型只能是基本数据类型,Class,String,enum)
- 可以通过default来声明参数的默认值
- 如果只有一个参数成员,一般参数名为value
注意:
源代码中我们经常看见在注解上还有一些注解例如,以下示例:
其中@Target与@Retention称之为元注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
什么是元注解
元注解(Meta-Annotation)是用于定义其他注解的注解。在Java中,注解是一种为代码提供元数据的机制,而元注解则是对这些注解进行进一步描述的工具。JDK中定义了四种标准的元注解类型:@Target、@Retention、@Documented和@Inherited。
- @Target:用于指定注解的作用目标,例如类、方法、字段等。
所修饰范围 | 取值ElementType |
---|---|
package | PACKAGE |
类、接口、枚举、Annotation类型 | TYPE |
类型成员(方法、构造方法、成员变量、枚举) | CONSTRUCTOR:用于描述构造器 FIELD:用于描述字段 METHOD:用于描述方法 |
方法参数和本地变量 | LOCAL_VARIABLE:用于描述局部变量 PARAMETER:用于描述参数 |
- @Retention:表示需要在什么级别保存该注释信息,用于指定注解的生命周期,即注解在何时生效,包括SOURCE(源码时有效)、CLASS(编译时有效)和RUNTIME(运行时有效)三种。
取值RetentionPolicy | 作用 |
---|---|
SOURCE | 在源文件中有效 |
CLASS | 在class文件中有效 |
RUNTIME | 在运行时有效,为Runtime可以被反射机制读取 |
- @Documented:用于指定将该注解包含在javadoc中。
- @Inherited:用于指定子类可以继承父类中的注解。
在自定义注解时,通常需要使用元注解来定义注解的属性、行为以及作用范围等。
通过元注解,开发者可以更加灵活地控制注解的使用和效果,从而实现更高级的功能。
元注解使用案例
使用@Target设置注解的作用目标是方法,则注解放在类上是就会报错.
MyAnnotation.java
package demo1;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
public @interface MyAnnotation {
}
AnnotationDemo.java
package demo1;
@MyAnnotation
public class AnnotationDemo {
@MyAnnotation
private void test(){}
}
编译结果:
反射机制读取注解
做一个简单User数据表与实体关系映射,通过反射解析创建生成表SQL
实体字段 | 表字段 | 备注 |
---|---|---|
id | int(10) | 主键 |
name | varchar2(30) | - |
表注解Table.java
package demo2.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 表名
*
* @author Anna.
* @date 2024/4/4 21:41
*/
@Target(ElementType.TYPE) // 设置作用范围
@Retention(RetentionPolicy.RUNTIME) // 设置生命周期
public @interface Table {
String value();
}
主键Id.java
package demo2.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 主键注解
*
* @author Anna.
* @date 2024/4/4 21:38
*/
@Target(ElementType.FIELD) // 设置作用范围
@Retention(RetentionPolicy.RUNTIME) // 设置生命周期
public @interface Id {
}
字段注解Field.java
package demo2.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 字段
*
* @author Anna.
* @date 2024/4/4 21:42
*/
@Target(ElementType.FIELD) // 设置作用范围
@Retention(RetentionPolicy.RUNTIME) // 设置生命周期
public @interface Field {
// 字段名称
String columnName();
// 类型
String type();
// 长度
int length();
}
实体UserDo.java
package demo2;
import demo2.annotation.Field;
import demo2.annotation.Id;
import demo2.annotation.Table;
/**
* |实体字段|表字段|备注|
* |:---|:---|:---|
* |id| int(10) | 主键 |
* |name| varchar2(30) |-|
*
* @author Anna.
* @date 2024/4/4 21:36
*/
@Table("USER_TABLE")
public class UserDo {
@Id
@Field(columnName = "id", type = "int", length = 10)
private Integer id;
@Field(columnName = "name", type = "varchar2", length = 30)
private String name;
public UserDo() {
}
public UserDo(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "UserDo{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
测试案例AnnotationDemo.java
package demo2;
import demo2.annotation.Id;
import demo2.annotation.Table;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Arrays;
/**
* 反射模拟处理注解新
*
* @author Anna.
* @date 2024/4/4 21:35
*/
public class AnnotationDemo {
public static void main(String[] args) throws Exception {
// 反射获取UserDo
String path = AnnotationDemo.class.getClassLoader().getResource("").getPath();
// System.out.println(path);
Class<?> clazz = Class.forName("demo2.UserDo");
// 初始化实例
UserDo userDo = (UserDo) clazz.getDeclaredConstructor().newInstance();
// 定义SQL 字段
StringBuffer sb = new StringBuffer();
sb.append("CREATE TABLE ");
// 获取表注解
Table table = clazz.getAnnotation(Table.class);
sb.append(table.value()).append(" {");
// 获取所有属性
Field[] fields = clazz.getDeclaredFields();
for (int i = 1; i <= fields.length; i++) {
Field field = fields[i - 1];
// 获取所有注解
Annotation[] annotations = field.getAnnotations();
String fieldStr = "";
String idStr = "";
for (Annotation a : annotations) {
if (a instanceof demo2.annotation.Field) {
demo2.annotation.Field a1 = (demo2.annotation.Field) a;
fieldStr = a1.columnName() + " " + a1.type() + "(" + a1.length() + ")";
} else if (a instanceof Id) {
idStr = " PRIMARY";
}
}
sb.append(fieldStr).append(idStr);
if (i < fields.length) {
sb.append(",");
}
}
sb.append("}");
System.out.printf("输出SQL:%s%n = ", sb.toString());
}
}
执行结果:
gitee源码
git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git