一、注解入门
注解(Annotation)是从JDK5.0开始引入的新技术。
Annotation的作用: – 不是程序本身,可以对程序作出解释。(这一点,跟注释没什么区别)
--可以被其他程序(比如:编译器等)读取。(注解信息处理流程,是注解和注释的重大区别 。如果没有注解信 息处理流程,则注解毫无意义)
Annotation的格式: – 注解是以“@注释名”在代码中存在的,还可以添加一些参数值。
Annotation在哪里使用? – 可以附加在package, class, method, field等上面,相当于给它们添加了额外的辅助信 息,我们可以通 过反射机制编程实现对这些元数据的访问。
二、内置注解
内置注解:顾名思义就时Java的JDK本身就提供好的一些注解供我们使用
@Override – 定义在java.lang.Override中,此注释只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明。
举例:Java中所有的类都默认继承了Object类,在Object类中有toString()方法,当你重写父类Object类的该方法时,通过添 加@Override会告诉编译器你重写了父类的该方法。
//Demo01默认继承自Object类,Object类中有toString()方法
public class Demo01 {
@Override
public String toString() {
return super.toString();
}
}
如果你使用@Override标注一个父类没有的方法,那么编译器会报错
当我们点击跟踪到上面代码中@Override时,可以看到@Override其实也是一个类
注解使用关键字@interface去标识
@Deprecated – 定义在java.lang.Deprecated中,此注释可用于修辞方法、属性、类 ,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更 好的选择。
举例:当我们调用Date()类的parse()方法时,可以看到parse()方法上有一条横线,表示该方法不建议使用
当进入parse() 方法中,可以看到该方法源码上被@Deprecated 注解标记
@SuppressWarnings – 定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息 。
该注解与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数值都是已经定义好了的,我们选择性的使用就好了,参数如下:
参数 说明
deprecation 使用了不赞成使用的类或方法时的警告
unchecked 执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型。
fallthrough 当 Switch 程序块直接通往下一种情况而没有 Break 时的警告。
path 在类路径、源文件路径等中有不存在的路径时的警告。
serial 当在可序列化的类上缺少 serialVersionUID 定义时的警告。
finally 任何 finally 子句不能正常完成时的警告。
all 关于以上所有情况的警告。
为什么该注解需要传递参数,那是因为这个注解类中有一个属性 “String[ ] value() ”,这代表了该注解使用时应该传递一个String数组类型的参数,注意这里的value()仅仅代表的是参数的名称而不是方法
使用@SuppressWarnings格式: @SuppressWarnings(value={"unchecked","depercation"})
介绍完了上面三种Java内置注解后,大家肯定还有很多疑问比如每个注解类上面的@target和@Retention
@Target:说明了Annotation所修饰的对象范围,比如TYPE就表明可以使用到类、接口、枚举上,FIELD表明可以使用到属性上等。
@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)
三、自定义注解、元注解
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
要点: – @interface用来声明一个注解
格式为:– public @interface 注解名 {定义体}
– 其中的每一个方法实际上是声明了一个配置参数。
– 方法的名称就是参数的名称 – 返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)
– 可以通过default来声明参数的默认值。 – 如果只有一个参数成员,一般参数名为value
注意: 注解元素必须要有值。我们定义注解元素时,经常使用空字符串、0作为默认值。 也经常使用负数(比如:-1)表示不存 在的含义
在我们自定义注解时通常需要加两个元注解
元注解:就是负责注解其他注解。 Java定义了4个标准的 meta-annotation类型,它们被用来提供对其它Annotation类型作说明。
以下是四个元注解的简单描述(元注解也是注解)
下面自定义了一个注解,使用@Target(value = ElementType.METHOD)表明该注解只能使用到方法上,要是用到类上或其他地方编译器会报错;使用@Retention(RetentionPolicy.RUNTIME)表明该注解是运行时有效
package com.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
* @author Xyz
* @create 2019-04-15-21:59
*/
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface XyzAnnotation01 {
}
四、反射机制读取注解
在使用Mybatis等框架时会了解一个概念:ORM(Object Relationship Mapping) 对象关系映射,因为存数据时一般都是面向关系型存储,但是我们编写的Java代码是类、属性、对象这样的存储方式,所以需要将类与表进行转化、属性与数据库字段转化、对象与数据库记录转化。 这时我们就能用注解+反射完成类与表的映射
我们对应于上图的数据库表进行编写程序,利用注解+反射与数据库建立关系。
1.首先创建对数据库名的注解
该注解需要传递一个参数:String value():用于表明对应那个数据库
package com.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String value();
}
2.创建对应数据库字段的注解
使用该注解时需要传递三个参数: 1:String columnName() 列名即字段名,对应于上图数据库表中的ID、name、age
2:String type() 表明字段的类型,比如ID字段类型为int
3:int length() 表明字段的长度
package com.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface filed {
String columnName();
String type();
int length();
}
3.创建对应于表的类
该类使用了@Table注解,传递的参数为“ tb_student ”,这个参数就是数据库名,在反射的时候可以读出来
在类中的每一个属性都用了@filed注解,传递进去的分别对应于数据库字段中的名称、类型、长度
package com.Annotation;
@Table("tb_student")
public class Student {
@filed(columnName = "id",type = "int",length = 10)
private int id;
@filed(columnName = "id",type = "varchar",length = 10)
private String studentName;
@filed(columnName = "id",type = "int",length = 3)
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
4.有了上面三步就可以使用反射读取类中的数据库名以及字段信息了
package com.Annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
//使用反射读取注解信息,模拟处理注解信息流程
public class Demo03 {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.Annotation.Student");
//获得类指定的注解
Table annotation = (Table)clazz.getAnnotation(Table.class);
System.out.println(annotation.value());
//获得类的属性的注解
Field studentName = clazz.getDeclaredField("studentName");
Annotation annotation1 = studentName.getAnnotation(filed.class);
System.out.println(((filed) annotation1).columnName());
System.out.println(((filed) annotation1).length());
System.out.println(((filed) annotation1).type());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
输出结果为:
可以看到利用反射+注解就可以把类中对应的数据库名以及字段读取出来了,这时就可以根据表名字段拼出DDL语句,然后使用JDBC执行