一、什么是注解
注意!是注“解”,不是注释,注释是在写代码时加上一些对代码的解释,它们两都起到了解释代码的作用
1.概念
从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
——百度百科
在Java中的注解是以@开头的,它会在编译,类加载,运行时被读取,然后由注解处理器来进行处理,注解仅仅是存放元数据,不会修改修饰对象的代码产生直接影响
注解和类、接口、数组、枚举等关键字平起平坐,同样重要
2.来源
在注解还没有出现之前,一般使用XML文件来存储元数据的,配置文件的信息还有SQL语句都可以算是元数据,这就使元数据和代码耦合度十分的低,如果项目十分大的话,就会造成维护困难,于是就诞生了注解,让元数据和代码紧密结合,极大的降低了编程的复杂度,在后来,注解功能就不仅仅局限与绑定元数据了
注解是真的好用,谁用谁知道
3.注解分类
- JDK自带的注解
- 来自第三方框架的注解
- 自定义注解
二、自定义注解
在上面三类注解中,我们主要关注的是自定义注解
1.元注解
元注解在自定义注解中需要用到,总共有4个,分别是@Target、@Retention、@Inherited、@Documented
@Target
这个注解是表示自定义注解的作用域,也就是说这个注解表明了定义的注解可以用来修饰什么类型的类、属性、方法
下面是 @Target的取值表 ,也不需要记,用的时候查看一下就好了
取值 | 注解使用范围 |
---|---|
METHOD | 可用于方法上 |
TYPE | 可用于类或者接口上 |
ANNOTATION_TYPE | 可用于注解类型上(被@interface修饰的类型) |
CONSTRUCTOR | 可用于构造方法上 |
FIELD | 可用于域上,就是类的属性/字段 |
LOCAL_VARIABLE | 可用于局部变量上,就是方法内部的属性 |
PACKAGE | 用于记录java文件的package信息 |
PARAMETER | 可用于参数上 |
@Resource中的@Target的value
@Target({TYPE, FIELD, METHOD})
@Retention
这个注解表示的是自定义注解的生命周期,也就是说这个注解能够决定自定义注解能够在那个阶段被处理,在那些阶段可以存在
下面是@Retention的取值表,同上
取值 | 生命周期 |
---|---|
RetentionPolicy.SOURCE | 只能存活在.java文件上,不会存活在.class文件,在经过编译器编译之后就不存在了 |
RetentionPolicy.CLASS | 能够存活在.class文件,不会存活在运行时期,也就是在内存中,但是在经过类加载器之后就不存在了 |
RetentionPolicy.RUNTIME | 能够存活在内存中,无论经过编译器还是类加载器都会存在,也是我们自定义注解时常用的 |
@Resource中的@Retention的value
@Retention(RUNTIME)
@Inherited
这个注解能够让子类继承父类上的注解,打个比方说,A继承了B,B上有这个注解,也有其他注解,那么A类就会继承B类上的其他注解。但是子接口的继承和实现都不会父接口的注解
这个注解没有value,直接使用就好了
@Documented
这个注解表示,在生成javadoc时,带了该注解的类是否要包含该自定义注解的信息,我们用不上。生成javadoc文档的方式有很多,用IDEA、javadoc.exe命令行
2.自定义注解语法
- 使用@interface关键字定义,跟使用class、interface、enum等关键字一样
-
定义注解类型元素(annotation type element)
定义注解类型元素才是我们的重点,第一,元素的访问修饰符必须为public;第二,元素的类型只能为基本数据类型(String、int、Class等)、还有枚举类型;第三、如果只有一个元素,则把元素名称取为value;第四,在元素名称后面加();第五,在()后面可以加default,后面接默认值
拉个@Retention注解来作例子
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
3.自定义注解
场景:类似于数据库的表格
Table
/**
* @author xxj
* 表注解
*/
@Target({TYPE})
@Retention(RUNTIME)
public @interface Table {
String value();
}
Column
/**
* @author xxj
* 行注解
*/
@Target(LOCAL_VARIABLE)
@Retention(RUNTIME)
public @interface Column {
String value();
}
4.使用自定义注解
定义了注解,当然也要使用注解啦,这里涉及到反射机制,如果还不了解的可以去看我的【java】反射机制
首先,先定义一个User类
/**
* @author xxj
* User表
*/
@Table("User")
public class User implements Serializable {
@Column("name")
private String name;
@Column("age")
private Integer age;
public User() {
}
//get、set、toString就不放上来了
}
然后,写一个Dome测试类
最重要的就是explainAnnotation()方法了,了解过反射的可以看一下
/**
* @author xxj
* 注解解析测试
*/
public class Demo {
public static void main(String[] args) {
User user=new User();
user.setName("xiaoming");
user.setAge(18);
User user1=new User();
user1.setName("xiaohong");
//调用方法解析注解
explainAnnotation(user);
explainAnnotation(user1);
}
private static void explainAnnotation(Object object){
//定义一个String来存放信息
String str="";
Class obClass=object.getClass();
//判断是否是Table注解
if (!obClass.isAnnotationPresent(Table.class)){
return;
}
//获取到table注解信息
Table table= (Table) obClass.getAnnotation(Table.class);
//获取table注解的value
String tableName=table.value();
str+="tableName="+tableName;
//获取object类的属性/字段
Field[] fields=obClass.getDeclaredFields();
//循环解析属性
for (Field field:fields) {
//判断是否是Column注解
if (!field.isAnnotationPresent(Column.class)){
continue;
}
//获取column注解信息
Column column= field.getAnnotation(Column.class);
//获取column注解的value
String columnName=column.value();
//拼接对应属性的getXxx()方法名称
String getMethodName="get"+columnName.substring(0,1).toUpperCase()
+columnName.substring(1);
//定义一个object对象来存放值
Object fieldValue = null;
try {
//获取对应属性的getXxx()方法
Method method=obClass.getMethod(getMethodName);
//调用方法
fieldValue=method.invoke(object);
}catch (Exception e){}
//拼接字符串
str+=","+columnName+":"+fieldValue;
}
System.out.println(str);
}
}
可以看到,注解的内容可以直接通过class类获得,但是对象的属性值只能通过对象获得,所以还是要使用method.invoke(object),将对象传递过去才能获得对象的属性值
三、总结
从上面的自定义注解和解析自定义注解中,我们可以看出创建了一个自定义的注解,不是直接使用它就有效果的,而是要另外写一个方法来解析这个注解,然后根据解析出来的注解内容在做相应的操作。
像MyBatis中提供的@mapper,就是用来判断这个类是否是有@mapper注解,而写在@select上的value,就可以直接拿来拼接SQL语句了。
——————————————————————————————
你知道的越多,不知道的越多。
如果本文章内容有问题,请直接评论或者私信我。如果觉得写得还不错的话,点个赞也是对我的支持哦
未经允许,不得转载!