本篇文章主要是作者学习注解的一些记录,希望能帮到您,如果有什么不妥当的地方希望得到指出,谢谢阅读
Java学习大纲:https://blog.csdn.net/weixin_39778570/article/details/94667501
JavaWeb:https://blog.csdn.net/weixin_39778570/article/details/97800485
请仔细阅读目录,点击可进行跳转
理解
下面这张图总结的挺好的,一开始开不太懂,可以看完后回顾一下
在定义注解的时候我们需要对我们的注解进行一些定义,也就是元注解,可以认为是注解的注解,主要的功能是给我们的注解生成一些标签,告诉编译器我们的注解应用于怎么样的场景。
而实现这些功能的东西你可以大概地称它为元标签,目前有下面几种元标签:
元注解是java API提供,是专门用来定义注解的注解,其作用分别如下:
@Target 表示该注解用于什么地方,可能的值在枚举类 ElemenetType 中,包括:
ElemenetType.CONSTRUCTOR----------------------------构造器声明
ElemenetType.FIELD --------------------------------------域声明(包括 enum 实例)
ElemenetType.LOCAL_VARIABLE------------------------- 局部变量声明
ElemenetType.METHOD ----------------------------------方法声明
ElemenetType.PACKAGE --------------------------------- 包声明
ElemenetType.PARAMETER ------------------------------参数声明
ElemenetType.TYPE--------------------------------------- 类,接口(包括注解类型)或enum声明
@Retention 表示在什么级别保存该注解信息。可选的参数值在枚举类型 RetentionPolicy 中,包括:
RetentionPolicy.SOURCE ---------------------------------注解将被编译器丢弃
RetentionPolicy.CLASS -----------------------------------注解在class文件中可用,但会被VM丢弃
RetentionPolicy.RUNTIME VM-------将在运行期也保留注释,因此可以通过反射机制读取注解的信息。
@Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。
相当与@see,@param 等。
@Inherited 允许子类继承父类中的注解。
Java本身提供的注解
JDK1.5之后内部提供的三个注解
@Deprecated 意思是“废弃的,过时的”
@Override 意思是“重写、覆盖”
@SuppressWarnings 意思是“压缩警告”
简单例子
我们在书写我们的注解的时候,理所当然应该写一个解释器,比如解释我们注解的类,不然我们的注解就没有发生作用了
编写一个简单的注解,注意:注解必须有值,所以一般default一个默认值
package myannotations.first;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 定义一个注解
* 描述包含id和description,最好有默认值default
* 注解元素:
* 基本类型
* String
* Class
* Enum
* Annotation
* @author Administrator
*
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
public int id(); // 这里不设置默认值进行测试,编译器要求使用注解的时候必须有一个值不能为null
public String description() default "not description";
}
使用注解
package myannotations.first;
import java.util.List;
/**
* 使用UseCase注解
* @author Administrator
*
*/
public class PasswordUtils {
@UseCase(id = 47, description = "Passwords must contain at least one numeric")
public boolean validatePassword(String password) {
return (password.matches("\\w*\\d\\w*"));
}
@UseCase(id = 48) // 这里必须给id赋值
public String encryptPassword(String password) {
return new StringBuilder(password).reverse().toString();
}
@UseCase(id = 49, description="New passwords can't equal previously used ones")
public boolean checkForNewPassword(List<String> prevPasswords, String password) {
return !prevPasswords.contains(password);
}
}
注解解释器
package myannotations.first;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 注解解释器
* @author Administrator
*
*/
public class UseCaseTracker {
public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
for(Method m : cl.getDeclaredMethods()) { // 读取类的方法
UseCase uc = m.getAnnotation(UseCase.class); // 读取方法的注解
if(uc != null) {
System.out.println("Found Use Case:" + uc.id() + " "
+ uc.description());
useCases.remove(new Integer(uc.id()));
}
}
for(int i : useCases) {
System.out.println("Warning Missing use case-" + i);
}
}
public static void main(String[] args) {
List<Integer> useCases = new ArrayList<Integer>();
Collections.addAll(useCases, 47,48,49,59);
trackUseCases(useCases, PasswordUtils.class);
}
}
实验结果
实现SQL语句的自动生成
我们在使用一些数据库框架的使用,我们不需要写SQL语句就能实现表的创建,这里我们也简单实现(当然框架里不会这么简单…)一下表的SQL语句的生成,当然你如果连接上了数据库,自然也可以自动生成表了,这里就没有实现对数据库的连接了
表的注解
package myannotations.second;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 数据库表注解
* @author Administrator
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
public String name() default "";
}
约束的注解
package myannotations.second;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
* 列约束
* @author Administrator
*
*/
@Target(ElementType.FIELD)
public @interface Constrains {
boolean primaryKey() default false;
boolean allowNull() default true;
boolean unique() default false;
}
Data类型的注解
package myannotations.second;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 列:Date
* @author Administrator
*
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLDate {
String name() default "";
Constrains constrains() default @Constrains;
}
整形类型的注解
package myannotations.second;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 列:整形
* @author Administrator
*
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
String name() default "";
Constrains constrains() default @Constrains;
}
字符串类型的注解
package myannotations.second;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 列:字符串
* @author Administrator
*
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
int value() default 0; // 若使用注解的使用,只使用一个注解元素,默认使用value
String name() default "";
Constrains constrains() default @Constrains;
}
表的主键的注解
package myannotations.second;
/**
* 定义主键
* @author Administrator
*
*/
public @interface Uniqueness {
Constrains constrains() default @Constrains(unique=true);
}
定义一张表,由它作为原型POJO对象生成我们的表SQL语句
package myannotations.second;
import java.util.Date;
/**
* 定义一个Bean,为表原型
* @author Administrator
*
*/
@DBTable(name = "t_member")
public class Member {
@SQLInteger(constrains = @Constrains(primaryKey = true, allowNull=false))
Integer id;
@SQLInteger
Integer age;
@SQLString(30)
String firstName;
@SQLString(value=50)
String lastName;
@SQLDate(name="birthday")
Date birthday;
/* getter和setter */
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
注解解释器
package myannotations.second;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class TableCreator {
public static void create(String[] classNames) throws ClassNotFoundException {
if(classNames.length < 1) {
System.out.println("没有要创建的表");
return;
}
// 枚举要创建的表
for(String className : classNames) {
// 获取原型类
Class<?> cl = Class.forName(className);
DBTable dbTable = cl.getAnnotation(DBTable.class);
if(dbTable == null) {
continue;
}
String tableName = dbTable.name();
// 如果没有定义表名,默认使用类名小写(当然,一般是驼峰改下划线)
if(tableName.length() < 1) {
tableName = cl.getName().toLowerCase();
}
// 列名
List<String> columnDefs = new ArrayList<String>();
for(Field field : cl.getDeclaredFields()) {
String columnName = null;
// 获取一个方法的所有注解
Annotation[] anns = field.getDeclaredAnnotations();
if(anns.length < 1) {
continue; // 没有列名
}
// 处理被SQLInteger修饰的注释
if(anns[0] instanceof SQLInteger) {
SQLInteger sInt = (SQLInteger) anns[0];
// 没有设置列名,按照属性名小写命名
if(sInt.name().length() < 1) {
columnName = field.getName().toLowerCase();
}else {
columnName = sInt.name();
}
columnDefs.add("`" + columnName + "` INT"
+ getConstrains(sInt.constrains()));
}
// 处理被SQLString修饰的注释
if(anns[0] instanceof SQLString) {
SQLString sString = (SQLString)anns[0];
// 没有设置列名,按照属性名小写命名
if(sString.name().length() < 1) {
columnName = field.getName().toLowerCase();
}else {
columnName = sString.name();
}
columnDefs.add("`" + columnName + "` VARCHAR(" + sString.value() + ")"
+ getConstrains(sString.constrains()));
}
// 处理被SQLDate修饰的注释
if(anns[0] instanceof SQLDate) {
SQLDate sDate = (SQLDate)anns[0];
// 没有设置列名,按照属性名小写命名
if(sDate.name().length() < 1) {
columnName = field.getName().toLowerCase();
}else {
columnName = sDate.name();
}
columnDefs.add("`" + columnName + "` Date"
+ getConstrains(sDate.constrains()));
}
}
// 生成完整的创建表的SQL语句
StringBuilder createCommand = new StringBuilder("CREATE TABLE `" + tableName + "` (");
for(String columnDef : columnDefs) {
createCommand.append("\n " + columnDef + ",");
}
String tableCreate = createCommand.substring(0, createCommand.length()-1) + ");";
System.out.println("Table Creation SQL for " + className + " is:\n"
+ tableCreate + "\n");
}
}
// 约束处理
private static String getConstrains(Constrains con) {
String constrains = "";
if(!con.allowNull()) {
constrains += " NOT NULL";
}
if(con.primaryKey()) {
constrains += " PRIMARY KEY";
}
if(con.unique()) {
constrains += " UNIQUE";
}
return constrains;
}
public static void main(String[] args) throws ClassNotFoundException {
String[] classNames = new String[]{"myannotations.second.Member"};
create(classNames);
}
}
实验结果: