注解的基本盘点 -- 《Java编程思想》
注解(元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在之后的某一个时刻非常方便地使用这些数据。 ---《Java编程思想》
其实注解可以理解为一个工具类,只要使用了这个工具类后,主体类将会添加一些功能,就好像一个法师身边多了一个小精灵。注解在一定程度上是把元数据和源代码文件结合在一起,而不是保存在外部文档中这一个大的趋势所催生的,不用去配置xml文件,不用去修改一些变量。之所以这么说注解,有注解本身特性所决定的,只要在类、方法、变量等代码的上方或者前方添加某个注解,那么我们将有这个注解的某个功能。
不得不说,注解是Java SE5重要语言之一,可以用来提供完整地描述程序所需的信息,存储程序的额外有关的信息。注解可以用来生成描述符文件,甚至或是新的类定义,有助于减轻编写“样板”代码的负担。
一、常用的Java内置的注解
- @Override,表示当前的的方法定义将覆盖父类中的方法。所以我们有时候觉得自己在子类中定义了一个和父类中存在的方法一样的名字,就可以自己覆盖了父类的方法,却没有发现其实有可能没有覆盖成功,原因有可能是argument的个数和类型有偏差,这个时候用了@Override我们就可以知道是否覆盖了,因为覆盖成功,@Overrdie不会报错,否则将会提示错误。
- @Deprecated,将某个element给注释为过时危险的element,不鼓励使用element,但是还是可以使用这个element。这个注解很多都是在类改造过程或者版本升级过程中使用到,为了兼顾旧版本,被引用的方法还能陪旧的版本使用。
@Deprecated
public static void sayHello(){
System.out.println("Hello!!!");
} - @SuppressWarnings,按照英文翻译,压制提醒,而且压制提醒的将会压制包含在压制element里面的element的,比如压制提醒了一个类,那么类里面的方法也可以被压制到。下列中的一个System.runFinalizersOnExit(true),是一个过期的方法,那么这个过期的方法被压制提醒后将不会再被提醒了。
@SuppressWarnings(value = { "deprecation" })
public static void main(String[] args) {
System.runFinalizersOnExit(true); }
二、定义注解
除了我们使用Java本身拥有的注解之外,我们更多要自己去定义注解,以满足各种个性化的需求。在很多框架,Spring,Mybatis中,注解是被使用非常频繁地一个Java工具。常见@Controller,@Component,@Service,@ResponseBody等等。下面就来看看这个定义中有方法和作用。
定义注解重要有两个元注解,@Target和@Retention,一个是注解作用的目标对象(FIELD,METHOD,CONSTRUCTOR),一个是注解作用的保持的一个生命周期(SOURCE,CLASS,RUNTIME),java源文件--》class文件--》内存中字节码。
例子一,用于密码的校验
- 定义注解,其中Target的目标是Method,用了ElementType.METHOD,而Retention则是RUNTIME,这个RUNTIME就是一个在编译和运行时都有效的一个标志。里面的内容有一个区分的id和描述的description。
package annotation; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase { public int id();
public String description() default "no description";
} - 应用注解,在PasswordUtils中应用了UseCase的注解。
package annotation; import java.util.List; public class PasswordUtils { @UseCase(id =47 ,description = "passwords must contain at lease one numeric")
public boolean validatePassword(String password){
return (password.matches("\\w*\\d\\w*"));
} @UseCase(id =48)
public String encryptPassword(String password){
return new StringBuilder(password).reverse().toString();
} @UseCase(id = 49,description = "New password can't equel previously used ones")
public boolean checkForNewPassword(List<String> prevPasswords, String password){
return !prevPasswords.contains(password);
}
} - 验证效果,我们会发现注解的很多部分都用到了反射机制中的方法,比如说是getDeclaredMethods得到PassUtils的中的方法,然后再通过getAnnotation去得到方法中的注解,再去根据注解中方法去拿到注解的值。
package annotation; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; 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,50);
trackUseCases(useCases,PasswordUtils.class);
}
} - 测试结果
Found Use Case:47 passwords must contain at lease one numeric
Found Use Case:48 no description
Found Use Case:49 New password can't equel previously used ones
Warning : Missing use Case -50
下面我们将进行一个定义注解在《Java编程思想》的一个很好的例子。目的是根据注解去生成一个SQL语句,这也是十分有用的。
- 定义一系列有关于生成数据库的注解
package annotation; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable { public String name() default "";
}package 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 Constraints { boolean primaryKey() default false;
boolean allowNull() default true;
boolean unique() default false;
}package 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 SQLString { int value() default 0;
String name() default "";
Constraints constraints() default @Constraints;
}package 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 SQLInteger { String name() default "";
Constraints constraints() default @Constraints;
} - 写出一个作用的类Member,然后在将我们上面所定义的注解应用到该注解中。
package annotation; @DBTable(name ="MEMBER")
public class Member { @SQLString(30) String firstName;
@SQLString(50) String lastName;
@SQLInteger Integer age;
@SQLString(value =30, constraints = @Constraints(primaryKey = true))
String handle;
static int memberCount;
public String getHandle(){return handle;}
public String getFirstName(){return firstName;}
public String getlastName(){return lastName;}
public String toString(){return handle;}
public Integer getAge(){return age;} } - 接下来,进行一个TableCreator,表格Sql的生成。运用了getAnnotation,getDeclaredFields,getDeclaredAnnotations等有关于反射的一系列的方法,去得到被注解应用的类中的各项属性的中值。
package annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List; public class TableCreator { public static void main(String[] args) throws Exception {
getSQL(new String[]{"annotation.Member"});
} public static void getSQL(String[] args) throws ClassNotFoundException {
if(args.length <1){
System.out.println("arguments : annotated classes");
System.exit(0);
}
for(String className :args){
Class<?> cl = Class.forName(className);
DBTable dbTable = cl.getAnnotation(DBTable.class);
if(dbTable == null){
System.out.println("No DBTable annotation in class " + className);
continue;
}
String tableName = dbTable.name();
//If the name is empty ,use the Class name;
if(tableName.length() <1){
tableName = cl.getName().toUpperCase();
}
List<String> columnDefs = new ArrayList<String>();
for(Field field : cl.getDeclaredFields()){
String columnName = null;
Annotation[] anns = field.getDeclaredAnnotations();
if(anns.length <1){
continue;//not a db table column
}
if(anns[0] instanceof SQLInteger){
SQLInteger sInt = (SQLInteger) anns[0];
//user field name if name not specified
if(sInt.name().length() < 1)
columnName = field.getName().toUpperCase();
else
columnName= sInt.name();
columnDefs.add(columnName + " INT" + getConstraints(sInt.constraints()));
}
if(anns[0] instanceof SQLString){
SQLString sString = (SQLString) anns[0];
//use field name if name not specified
if(sString.name().length() <1){
columnName = field.getName().toUpperCase();
}else{
columnName = sString.name();
}
columnDefs.add(columnName + " VARCHAR(" +sString.value() + ")"
+getConstraints(sString.constraints()));
}
StringBuilder createCommand = new StringBuilder(
"CREATE TABLE " + tableName +"(");
for(String columnDef : columnDefs)
createCommand.append("\n " + columnDef + ",");
//Remove trailing comma
String tableCreate = createCommand.substring(0,createCommand.length() -1) +");";
System.out.println("Table Creation SQL for " + className + " is :\n" + tableCreate);;
} }
} private static String getConstraints(Constraints con) {
// TODO Auto-generated method stub
String constraints = "";
if(!con.allowNull())
constraints += "NOT NULL";
if(con.primaryKey())
constraints += "PRIMARY KEY";
if(con.unique())
constraints += "UNIQUE";
return constraints;
}
} - 运行的结果
Table Creation SQL for annotation.Member is :
CREATE TABLE MEMBER(
FIRSTNAME VARCHAR(30));
Table Creation SQL for annotation.Member is :
CREATE TABLE MEMBER(
FIRSTNAME VARCHAR(30),
LASTNAME VARCHAR(50));
Table Creation SQL for annotation.Member is :
CREATE TABLE MEMBER(
FIRSTNAME VARCHAR(30),
LASTNAME VARCHAR(50),
AGE INT);
Table Creation SQL for annotation.Member is :
CREATE TABLE MEMBER(
FIRSTNAME VARCHAR(30),
LASTNAME VARCHAR(50),
AGE INT,
HANDLE VARCHAR(30)PRIMARY KEY);
三、现阶段中很多在运用到注解的例子
- JUnit
- Spring
- SpringMVC
- MyBatis
- Hibernate
注解的基本盘点 -- 《Java编程思想》的更多相关文章
- 《Java编程思想》读书笔记
前言 这个月一直没更新,就是一直在读这本<Java编程思想>,这本书可以在Java业界被传神的一本书,无论谁谈起这本书都说好,不管这个人是否真的读过这本书,都说啊,这本书很好.然后再看这边 ...
- 《Java编程思想第四版完整中文高清版.pdf》-笔记
D.2.1 安插自己的测试代码 插入下述“显式”计时代码,对程序进行评测: long start = System.currentTimeMillis(); // 要计时的运算代码放在这儿 long ...
- 《JAVA编程思想》第四版 PDF
感谢,参考:https://www.cnblogs.com/buwuliao/p/8073211.html 一.链接: 中文版: https://pan.baidu.com/s/1d07Kp4 密码: ...
- 《JAVA编程思想》第四版 PDF 下载 中文版和英文版 高清PDF扫描带书签
一.链接: 中文版: https://pan.baidu.com/s/1d07Kp4 密码:x2cd 英文版: https://pan.baidu.com/s/1boOSdAZ 密码: rwgm 文件 ...
- 再读《Java编程思想 》
前段时间在豆瓣上无意间看到一个帖子"我为什么把thinking in java 读了10遍",是11年的帖子,下面评论至今,各种声音都有,不过大多数还是佩服和支持的.我个人来讲也是 ...
- Java编程思想(第4版) 中文清晰PDF完整版
Java编程思想(第4版) 中文清晰PDF完整版 [日期:2014-08-11] 来源:Linux社区 作者:Linux [字体:大 中 小] <Java编程思想>这本书赢得了全 ...
- JAVA编程思想——分析阅读
需要源码.JDK1.6 .编码风格参考阿里java规约 7/12开始 有点意识到自己喜欢理论大而泛的模糊知识的学习,而不喜欢实践和细节的打磨,是因为粗心浮躁导致的么? cron表达式使用 设计能力.领 ...
- Java编程思想 笔记
date: 2019-09-06 15:10:00 updated: 2019-09-24 08:30:00 Java编程思想 笔记 1. 四类访问权限修饰词 \ 类内部 本包 子类 其他包 publ ...
- 《Java编程思想》读书笔记(二)
三年之前就买了<Java编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第一章到第十章的内容,这一次记录的是第 ...
随机推荐
- 【POJ】3744 Scout YYF I
http://poj.org/problem?id=3744 题意:直线上n个地雷,n<=10,范围在[1, 100000000],每一次有p的概率向前走一步,1-p的概率向前走两步,问安全通过 ...
- 【BZOJ1951】【SDOI2010】古代猪文 Lucas定理、中国剩余定理、exgcd、费马小定理
Description “在那山的那边海的那边有一群小肥猪.他们活泼又聪明,他们调皮又灵敏.他们自由自在生活在那绿色的大草坪,他们善良勇敢相互都关心……” ——选自猪王国民歌 很久很久以前,在山的那边 ...
- Android -- 滑式抽屉SlidingDrawer(非原创)
SlidingDrawer(滑动式抽屉)隐藏屏外的内容,并允许用户拖拽一个handle以显示隐藏的内容.SlidingDrawer可以在垂直或者水平使用.它由两个子视图组成:一个是用户拖拽的handl ...
- CentOS 6.5/6.6 安装mysql 5.7 最完整版教程
Step1: 检测系统是否自带安装mysql # yum list installed | grep mysql Step2: 删除系统自带的mysql及其依赖命令: # yum -y remove ...
- GO语言练习:网络编程 ICMP 示例
1.代码 2.编译及运行 1.Go语言网络编程:ICMP示例代码 icmptest.go package main import ( "fmt" "net" & ...
- 如何打印出lua里table的内容
不像开发as3时用fb有强大的断点调试功能,一般lua开发不用什么高级的ide,貌似也没有适合的,就直接用sublime.exvim等文本编辑器,直接编译运行看结果.所以不能很方便的知道变量值,特别是 ...
- 将bootstrap弹出框的点击弹出改为鼠标移入弹出
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- android-ListView控件的使用
一.深刻理解ListView 1.职责:将数据填充到布局.响应用户操作 2.ListView的实现需要:布局.数据源.适配器 3.常见适配器: ArrayAdapter<T> 用来绑定一 ...
- Linux_文件查看
文件查看 直接查看内容:cat , tac , nl 翻页查看:more , less 指定获取内容:head , tail 查看非纯文字文档:od 文件时间更新与新建:touch cat: 从首行开 ...
- 在Apache中使用mod_rewrite模块重写URL
如果有使用第三方框架做项目时,url路径是可以同过框架给的方法来设定的(如thinkphp),但如果使用原生php写的项目又想重写url,则可通过apache的一些设置来达到想要的效果. 在更改apa ...