摘要:引言在用的时候发现能自动生成,同时带有一些注解,这引起了我的好奇。注解来源于之类的其他语言。关闭不当的编译器警告。允许子类继承父类中的注解。五通过注解反射生成语句接下来,我用一个例子来解释注解的作用。
引言
在用hibernate的时候发现idea能自动生成JavaBean,同时带有一些注解,这引起了我的好奇。当在学习Android的时候,我发现XUtils这个工具包中的DBUtils也能够使用类似hibernate的注解。于是乎在java编程思想中找了找有关注解的用法。
一 注解定义注解(也称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据。注解来源于C#之类的其他语言。
注解的语法比较简单,除了@符号外,它与java的固有语法一致。javaSE5中内置了三种注解:
二 基本语法@Override:定义覆盖超类,当覆写对应不上被覆盖的方法,编译器发出错误提示。
@Deprecated:当使用了该注解,即表示这个方法已经不推荐被使用。
@SuppressWarnings:关闭不当的编译器警告。
我们使用自定义的注解对一个方法进行注解:
public class Testable{ public void execute() { System.out.println("execute..."); } @WETest void taskStart() { execute(); } }
在上边的代码中,我们对taskStart方法使用了注解,接下来我们对WETest注解进行定义:
import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface WETest{}三 定义注解
我们给上边的注解添加一些内容:
import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface WETest{ public int id(); public String Notes() default "there is no Notes"; }
同样,我们对Testable类使用最新的注解:
public class Testable{ @WETest(id=666) public void execute() { System.out.println("execute..."); } @WETest(id=666,Notes="this is a method") void taskStart() { execute(); } }
注解就是这么使用的,当注解内容没有填写时,他会使用默认的值,如execute方法,他没有定义Notes,那么Notes默认值为"there is no Notes"。
四 元注解我们看到注解上边有两行内容,它们是元注解,专门对注解的解释。元注解一共有四种,分别是:
五 通过注解反射生成SQL语句@Target:表示该注解可以用到哪些地方,ElementType,CONSTRUCTOR构造器声明,FIELD域声明(包括enum实例),LOCAL_VARIABLE局部变量声明,METHOD方法,PACKAGE包,PARAMETER参数,TYPE类、接口或enum。
@Retention:表示需要在什么级别上使用,RetentionPolicy,SOURCE注解会被编译器丢掉,CLASS在class文件中可用会被VM抛弃,RUNTIME在VM运行期也会保留可以通过反射获取注解信息。
@Documented:将注解包含在Javadoc中。
@Inherited:允许子类继承父类中的注解。
接下来,我用一个例子来解释注解的作用。先编写一些注解定义:
//DBTable.java 用来生成数据表 package annotations; 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 ""; } //Constraints.java 用来定义约束项 package annotations; 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; } //PrimaryKey.java 将Constraints中的primarykey定义为真,表示为主键 package annotations; import java.lang.annotation.*; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface PrimaryKey { Constraints constraints() default @Constraints(primarykey = true); } //SQLInteger.java 定义列的类型 package annotations; import java.lang.annotation.*; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLInteger { String name() default ""; Constraints constraints() default @Constraints; } //SQLString.java 定义列的类型 package annotations; import java.lang.annotation.*; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLString { int value() default 64; String name() default ""; Constraints constraints() default @Constraints; } 接下来写一个javabean,使用上述注解: //User.java import annotations.Constraints; import annotations.DBTable; import annotations.SQLInteger; import annotations.SQLString; @DBTable(name="user") public class User { @SQLInteger(name="id",constraints = @Constraints(primarykey=true)) public Integer id; @SQLString(value=30) public String name; @SQLString(name="passwd",constraints=@Constraints(allownull=false)) public String password; /*可以不用 public void setId(Integer id) { this.id = id; } public void setName(String name) { this.name = name; } public void setPassword(String password) { this.password = password; } public Integer getId() { return id; } public String getName() { return name; } public String getPassword() { return password; }*/ }
我们看到注解中可以使用注解,在SQLInteger中我们使用了Constraints注解。
接下来我们写一个注解处理器:
//Test.java import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Scanner; import annotations.Constraints; import annotations.DBTable; import annotations.SQLInteger; import annotations.SQLString; public class Test { public static String getConstraints(Constraints con) { String constraints = ""; if(!con.allownull()) { constraints +=" NOT NULL"; } if(con.primarykey()) { constraints += " PRIMARY KEY"; } return constraints; } public static void main(String[] args) throws ClassNotFoundException { Scanner s = new Scanner(System.in); String name = s.next(); //从控制台输入一个类名,我们输入User即可 Class> cl = Class.forName(name); //加载类,如果该类不在默认路径底下,会报 java.lang.ClassNotFoundException DBTable dbTable = cl.getAnnotation(DBTable.class); //从User类中获取DBTable注解 if(dbTable == null){ //如果没有DBTable注解,则直接返回,我们写了,当然有 return; } String tableName = (dbTable.name().length()<1)?cl.getName():dbTable.name();//获取表的名字,如果没有在DBTable中定义,则获取类名作为Table的名字 ListcolumnDefs = new ArrayList (); for(Field field : cl.getDeclaredFields()) //获取声明的属性 { String columnName = null; Annotation[] anns = field.getDeclaredAnnotations();//获取注解,一个属性可以有多个注解,所以是数组类型 if(anns.length < 1) { continue; } if(anns[0] instanceof SQLInteger) //判断注解类型 { SQLInteger sInt = (SQLInteger)anns[0]; columnName = (sInt.name().length()<1)?field.getName():sInt.name();//获取列名称与获取表名一样 columnDefs.add(columnName+" INT"+getConstraints(sInt.constraints()));//使用一个方法,自己写的getConstraints(Constraints constraints)获取列定义 } if(anns[0] instanceof SQLString) { SQLString sStr = (SQLString)anns[0]; columnName = (sStr.name().length()<1)?field.getName().toUpperCase():sStr.name(); columnDefs.add(columnName + " VARCHAR("+sStr.value()+")"+getConstraints(sStr.constraints())); } } StringBuilder createCommand = new StringBuilder("CREATE TABLE "+tableName+"("); for(String columnDef :columnDefs) { createCommand.append(" "+columnDef+","); } String tableCreate = createCommand.substring(0,createCommand.length()-1)+" );"; System.out.println(tableCreate); //打印出来 } }
我们可以采用上述方法动态的处理一些数据,例如创建数据表。
六 总结注意:注解不支持继承例如 extends @xxx。 注解的default默认值不可以为null
使用注解可以减少对xml等外部文件的依赖,使得对类的定义可以在一处实现,避免了一个类两处定义的麻烦。spring和hibernate就采用的这样的方法。
更多文章:http://blog.gavinzh.com
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/64375.html
摘要:文章系列从零入门系列之从零入门系列之程序结构设计说明前言本篇文章开始代码实践,系统设计从底向上展开,因此本篇先介绍如何实现数据库表实体类的设计实现。主键由数据库自动生成主要是自动增长型主键由程序控制。 文章系列 【从零入门系列-0】Sprint Boot 之 Hello World 【从零入门系列-1】Sprint Boot 之 程序结构设计说明 前言 本篇文章开始代码实践,系统...
摘要:入门笔记简介是一种基于的实现了设计模式的请求驱动类型的轻量级框架,是系开源项目中的一个,和配合使用。配置在中需要添加使用的和映射规则。入门较快,而掌握起来相对较难。 SpringMVC入门笔记 1. 简介 Spring MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架 ,是Spring系开源项目中的一个,和IoC配合使用。通过策略接口,Spring...
摘要:一定义是一款优秀的持久层框架,它支持定制化存储过程以及高级映射。别名与类中的属性名保持一致。接口的名字建议为,与文件保持一致编写文件,名字与接口名保持一致。 一、定义 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射...
阅读 3994·2021-11-22 13:53
阅读 3593·2021-11-19 11:29
阅读 1183·2021-09-08 09:35
阅读 3137·2020-12-03 17:26
阅读 491·2019-08-29 16:06
阅读 2090·2019-08-26 13:50
阅读 1157·2019-08-23 18:32
阅读 2127·2019-08-23 18:12