1. 注解
什么注解?
注解:annotation(标识,标签),从Java5开始支持注解
注解能干什么?
注解是贴在java程序元素上面
程序元素 : 类,方法,字段,方法参数,接口,构造函数,枚举
注解贴在程序上面有什么用?
在反射的时候,动态可以获取字节码,方法,字段等等程序元素,获取了这些程序元素,那么就能获取程序元素上贴的注解。这些注解会参与程序运行提供比较的相关信息和数据
枚举是一个特殊类
注解是一个特殊的接口,所有的注解都继承自java.lang.annotation这个接口。
完整的注解(从编写到最终运行)需要三方面的参与。
1.需要定义一个注解。
2.需要一个被贴的程序元素(类,方法,字段,构造器等)
3.第三方程序的支持(赋予我注解的特殊功能)
1.1. JDK中内置的注解
1.@Override 限定覆写父类方法
2.@Deprecated 标记已过时的成员,被标记的方法不推荐使用.
问题1:有的注解可以贴在类上,方法上,字段上,有的却只能贴在类上
问题2:有的注解可以有一个或者多个参数,有的却不行。
|
1.2. JDK中的元注解
注解: 贴在程序元素上面的标签
元注解 : 注解的注解(贴在注解上面的注解)
元注解 主要用于限定当前的注解能够贴在哪儿?能够保留在哪个阶段(程序执行三个阶段
源代码阶段,字节码阶段,JVM中)
@Retention: 表示注解可以保存在哪一个时期.
保存的时期的值,封装在RetentionPolicy枚举类中
枚举常量摘要
|
CLASS
|
注解保留到字节码阶段,运行时候失效了
|
RUNTIME
|
注解保留到运行阶段,运行时候使用反射获取做相应的程序处理-一般开发者自定注解都保留运行阶段
|
SOURCE
|
注解在源代码阶段有效,编译字节码就失效了
|
|
@Target: 表示注解可以贴在哪些位置(类,方法上,构造器上等等).
位置的常量封装在ElementType枚举类中:
ElementType.ANNOTATION_TYPE只能修饰Annotation
ElementType.CONSTRUCTOR只能修饰构造方法
ElementType.FIELD只能修饰字段(属性),包括枚举常量
ElementType.LOCAL_VARIABLE只能修饰局部变量
ElementType.METHOD只能修饰方法
ElementType.PACKAGE只能修饰包(极少使用)
ElementType.PARAMETER只能修饰参数
ElementType.TYPE只能修饰类,接口,枚举
1.3. 自定义注解
1. 定义一个注解
语法 : 注解关键字 @Interface
2. 被贴的程序元素
3. 第三方程序参与赋予注解功能(反射程序)
程序代码
package cn.zj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 设置注解的元注解
* 1,Target
* 注解可以贴在那些程序元素上面
* 2, Retention
* 注解可以保留到那个阶段,一般自定义保留到RUNTIME运行时
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
/**
* 注解属性
* 语法
* 数据类型 属性名称();
* 如果属性名称是 value ,在使用注解的时候,可以省略 value
*/
//String value();
String name();
}
|
package cn.zj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value();
}
|
package cn.zj.pojo;
import cn.zj.annotation.Column;
import cn.zj.annotation.Table;
/**
* @Table 注解的作用就是为了解决在反射时候,实体类和 表明不匹配
* 实体类 :User --> user 理论上对应数据表 user
* 实际上数据库表名 :t_user
* 这样如果默认不匹配 反射时候对不上,反射封装存储数据就失败
*/
@Table(name="t_user")
public class User {
private Integer id;
@Column("username")
private String name;
private String password;
private String email;
private String phone;
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public String getPassword() {
return password;
}
public String getEmail() {
return email;
}
public String getPhone() {
return phone;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
public void setEmail(String email) {
this.email = email;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
|
测试代码
package cn.zj.test;
import cn.zj.annotation.Column;
import cn.zj.annotation.Table;
import cn.zj.pojo.User;
import java.lang.reflect.Field;
public class AnnotationTest {
//使用反射获取字节码,并获取对应元素的注解
public static void main(String[] args) {
//1.获取User类的字节码实例
Class<User> clz = User.class;
//2.判断类上面是否有 @Table注解
boolean flag = clz.isAnnotationPresent(Table.class);
if(flag){
//1.获取@Table注解
Table table = clz.getAnnotation(Table.class);
System.out.println(table);
//2.获取具体的属性值
String tableName = table.name();
System.out.println(tableName);
}
//2.获取所有字段
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
//1.判断字段上是否有注解
if(field.isAnnotationPresent(Column.class)){
//2.获取字段上的注解
Column column = field.getAnnotation(Column.class);
System.out.println(column);
}
}
}
}
|