目录
一.注解分类
1.按照作用域分
根据注解的作用域@Retention,注解分为
RetentionPolicy.SOURCE: Java源文件上的注解
RetentionPolicy.CLASS: Class类文件上的注解
RetentionPolicy.RUNTIME: 运行时的注解
2.按照来源分
按照注解的来源,也是分为3类
1. 内置注解 如@Override ,@Deprecated 等等
2. 第三方注解,如Hibernate, Struts等等
3. 自定义注解,如仿hibernate的自定义注解
在工作中,大部分都是使用第三方注解, 当然第三方注解本身就是自定义注解。 本教程的主要作用是帮助大家理解这些第三方注解是如何工作的,让大家用得心里踏实一些。
二.内置注解
@Override
@Deprecated
@SuppressWarnings
@SafeVarargs
@FunctionalInterface
了解就好
三.定义注解(元注解)
在讲解元注解概念之前,我们先建立元数据的概念。 元数据在英语中对应单词 metadata, metadata在wiki中的解释是:
Metadata is data [information] that provides information about other data 为其他数据提供信息的数据
这样元注解就好理解了,元注解 meta annotation用于注解 自定义注解 的注解。
元注解有这么几种:
@Target
@Retention
@Inherited
@Documented
@Repeatable (java1.8 新增)
常用习惯:
Target:必须设置
Retention:一般设置为RUNTIME
通常不必写@Inherited, @Repeatable等等
当注解的方法是value的时候,给这个注解赋值时,本来应该是:@MyColumn(value="name_")
现在可以简略一点,写为@MyColumn("name_") 只有当名称是value的时候可以这样,其他名称如name,stratgy等不行
1.@Target 表示这个注解能放在什么位置上,是只能放在类上?还是即可以放在方法上,又可以放在属性上。
可以选择的位置列表如下:
ElementType.TYPE:能修饰类、接口或枚举类型
ElementType.FIELD:能修饰成员变量
ElementType.METHOD:能修饰方法
ElementType.PARAMETER:能修饰参数
ElementType.CONSTRUCTOR:能修饰构造器
ElementType.LOCAL_VARIABLE:能修饰局部变量
ElementType.ANNOTATION_TYPE:能修饰注解
ElementType.PACKAGE:能修饰包
2.@Retention 表示生命周期,自定义注解@JDBCConfig 上的值是 RetentionPolicy.RUNTIME, 表示可以在运行的时候依然可以使用。
@Retention可选的值有3个:
RetentionPolicy.SOURCE: 注解只在源代码中存在,编译成class之后,就没了。@Override 就是这种注解。
RetentionPolicy.CLASS: 注解在java文件编程成.class文件后,依然存在,但是运行起来后就没了。@Retention的默认值,即当没有显式指定@Retention的时候,就会是这种类型。
RetentionPolicy.RUNTIME: 注解在运行起来之后依然存在,程序可以通过反射获取这些信息.
3.@Inherited 表示该注解具有继承性。子类可以获取被注解父类的注解
4.@Documented 在用javadoc命令生成API文档后,文档里会出现该注解说明。
5.当没有@Repeatable修饰的时候,注解在同一个位置,只能出现一次,如例所示:
@JDBCConfig(ip = "127.0.0.1", database = "test", encoding = "UTF-8", loginName = "root", password = "admin")
@JDBCConfig(ip = "127.0.0.1", database = "test", encoding = "UTF-8", loginName = "root", password = "admin")
重复做两次就会报错了。
使用@Repeatable之后,再配合一些其他动作,就可以在同一个地方使用多次了。
四.自定义注解
使用反射API读取Annotation:
//判断是否存在注解
Class.isAnnotationPresent(Class)
Constructor.isAnnotationPresent(Class)
Field.isAnnotationPresent(Class)
Method.isAnnotationPresent(Class)
//获取注解
Class.getAnnotation(Class)
Constructor.getAnnotation(Class)
Field.getAnnotation(Class)
Method.getAnnotation(Class)
getParameterAnnotations()
1.不使用注解
//不是用注解
public class DbUtil {
static String ip="127.0.0.1";
static int port=3306;
static String database="students";
static String encoding="utf-8";
static String loginName="root";
static String password="12345678";
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection(){
Connection connection=null;
try {
String url=String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s",ip,port,database,encoding);
connection= DriverManager.getConnection(url,loginName,password);
}catch (Exception e){
e.printStackTrace();
}
return connection;
}
}
2.使用注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface JDBCConfig {
String ip();
int port() default 3306;
String database();
String encoding();
String loginName();
String password();
}
@JDBCConfig(ip="127.0.0.1",port = 3306,database = "students",encoding = "utf-8",loginName = "root",password = "12345678")
public class DbUtil {
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection(){
Class clazz=DbUtil.class;
JDBCConfig config= (JDBCConfig) clazz.getAnnotation(JDBCConfig.class);
String ip=config.ip();
int port=config.port();
String database=config.database();
String encoding=config.encoding();
String loginName=config.loginName();
String password=config.password();
Connection connection=null;
try {
String url=String.format("jdbc:mysql://%s:%d/%s?characterEncoding=%s",ip,port,database,encoding);
connection= DriverManager.getConnection(url,loginName,password);
}catch (Exception e){
e.printStackTrace();
}
return connection;
}
}
五.仿Hibernate 的注解
参考hibernate的 注解配置方式 ,自定义5个注解,分别对应hibernate中用到的注解:
hibernate_annotation.MyEntity 对应 javax.persistence.Entity
hibernate_annotation.MyTable 对应 javax.persistence.Table
hibernate_annotation.MyId 对应 javax.persistence.Id
hibernate_annotation.MyGeneratedValue 对应 javax.persistence.GeneratedValue
hibernate_annotation.MyColumn 对应 javax.persistence.Column
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyEntity {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTable {
String name();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyId {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyGeneratedValue {
String strategy();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyColumn {
String value();
}
@MyEntity
@MyTable(name ="student")
public class Student2 {
private int id;
private String name;
private int age;
@MyId
@MyGeneratedValue(strategy = "identity")
@MyColumn("id_")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@MyColumn("name_")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@MyColumn("age_")
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public static void main(String[] args){
Class clazz= Student2.class;
MyEntity entity=(MyEntity) clazz.getAnnotation(MyEntity.class);
if(entity==null){
System.out.println("这个类不是实体类");
return;
}
System.out.println(clazz.getSimpleName()+"是实体类");
//否则是实体类
MyTable table=(MyTable) clazz.getAnnotation(MyTable.class);
System.out.println("其对应的表名为:"+table.name());
Method[] methods=clazz.getMethods();
for(Method method:methods){
boolean isExistIdAnnotation=method.isAnnotationPresent(MyId.class);
if(isExistIdAnnotation){
System.out.println("找到主键为:"+ method2Field(method.getName()));
MyGeneratedValue generatedValue=method.getAnnotation(MyGeneratedValue.class);
System.out.println("其自增长策略为:"+generatedValue.strategy());
MyColumn column=method.getAnnotation(MyColumn.class);
System.out.println("对应的数据库列名为:"+column.value());
}
}
for(Method method:methods){
boolean isExistIdAnnotation=method.isAnnotationPresent(MyId.class);
if(isExistIdAnnotation)continue;
boolean isExistColumnAnnotation=method.isAnnotationPresent(MyColumn.class);
if(isExistColumnAnnotation){
MyColumn column=method.getAnnotation(MyColumn.class);
System.out.println(method2Field(method.getName())+" 对应的数据库列名为:"+column.value());
}
}
}
public static String method2Field(String methodName){
String result="";
result=methodName.replaceFirst("get","");
return result.length()<=0?"":result.toLowerCase();
}