注解的基本盘点 -- 《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编程思想>这本书,但是到现在为止都还没有好好看过这本书,这次希望能够坚持通读完整本书并整理好自己的读书笔记,上一篇文章是记录的第一章到第十章的内容,这一次记录的是第 ...
随机推荐
- Crystal Reports 2008(水晶报表) 第一个报表
学习Craystal Reports 2008的时候,光看说明文档,很多东西看了就忘了. 我在看文档的时候,是跟着文档上面来做的. 这样边看边做,效果还不错哈 下面就是我的第一个demo 先看看效果: ...
- Linux_CentOS6.5安装vncserver实现图形化访问
一. 安装gnome图形化桌面 #yum groupinstall -y "X Window System" #yum groupinstall -y "Desktop& ...
- Linux下memcached安装和启动方法
Linux下memcached安装和启动方法 1. 首先下载memcached 和 libevent 包. Memcached用到了libevent这个库用于Socket的处理.下面是下载的两个包文件 ...
- [zt] ROI (Region of Interest) 感兴趣区域 OpenCV
在以前介绍IplImage结构的时候,有一个重要的参数——ROI.ROI全称是”Region Of Interest”,即感兴趣的区域.实际上,它是IPL/IPP(这两个是Inter的库)结构IplR ...
- jdbc模拟电话本。
1 项目描述 该项目是用于日常生活中记录联系人信息的一款小工具. 实现了对联系人的姓名.年龄.性别.电话号码.住址的添加及修改.查找.删除.排序等功能.该项目是以windows控制台为运行平台,所有的 ...
- u盘安装windows系统
使用老毛桃为例: 电脑下载老毛桃到自己电脑,插入U盘,制作U盘为启动盘. 四种安装方法: 1.win7能够使用:(win中包含iso的解压文件)解压ISO ----〉 restart win7 --- ...
- 树莓派3b+ 用samba与windows共享文件
1. 树莓派安装samba sudo apt-get install samba 2. 设置一个公共目录 cd /;sudo mkdir share;sudo chmod 777 sharesudo ...
- app设计需注意的
手机上同步photoshop设计稿: ps play应用 设计: 资源: 1.音乐上传问题 音乐控制在2M以内,推荐使用[格式工厂]进行压缩. 2.视频上传问题 为了保证在线的播放效果,上传的视频大小 ...
- .net 文件下载【转】
方式一:TransmitFile实现下载.将指定的文件直接写入 HTTP 响应输出流,而不在内存中缓冲该文件. protected void Button1_Click(object send ...
- eclipse中如何修改dynamic web module version
java项目中,若切换服务器,经常会涉及到动态web模块版本的问题. 比如:新建了web项目,开始使用tomcat服务器,但是后来使用jboss服务器,就会出现:Project facet ...