Java注解简介、自定义注解及模拟Junit、模拟hibernate根据实体类建表
注解简介
注解:JDK1.5的新特性
注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。
Java SE5 三个内置标准注解
- @Override:方法覆盖、重写;
- @Deprecated:过时的;
- @SupperessWornings:关闭不当的编译器警告信息;
元注解:
-
@Target:表示注解在什么地方使用,可用ElementType,其值为:
* constructor:说明该方法用在构造方法上;
* field:说明盖注解用在属性上;
* local_variable:局部变量上;
* method:用在方法上;
* package:用在包声明上;
* parameter:用在参数上;
* type:用在类或接口上; -
@Retention:表示需要在什么级别保存该注解信息,可能的参数值RetentionPolicy为:
source:表示该注解会被编译器丢弃
class:说明该注解会在.class文件中,但会被JVM丢弃
runtime:jvm将在运行期间保留,因此可以通过反射机制来读取注解信息 -
@Documented:将该注解包含在JavaDoc中。表示此注解会被javadoc工具提取成文档。
-
@Inherited:允许子类继承父类中的注解。
自定义注解
- 定义注解
import java.lang.annotation.*;
@Target(ElementType.METHOD) //说明此注解用在方法上
@Retention(RetentionPolicy.RUNTIME) //说明是运行级别
public @interface Info {
int id(); //为区分接口与类,在后面加上()
String des() default "暂无信息";
}
- 定义目标类
public class TestInfo {
@Info(id=1,des="show方法")
public void show() {
System.out.println("阴雨绵绵。。。");
}
@Info(id=2)
public String getInfo() {
return "欸。。。";
}
public void description(){
System.out.println("真是应景。。。");
}
}
- 定义测试类
public class InfoTracker {
public static void main(String[] args) {
test(TestInfo.class);
}
public static void test(Class<TestInfo> cl) {
Info info = null;
for( Method method : cl.getDeclaredMethods() ){ //循环给定类中的所有方法。也可以给定包路径,自动扫描该包下的所有类
if( method.isAnnotationPresent( Info.class ) ){
//method.getAnnotations(); //获取这个方法上的所有注解
//现在我们只想知道是否有我们给定的注解Info
System.out.println( method.getName() + "有Info注解" );
info = method.getAnnotation(Info.class);
System.out.println(info.id() + "-" + info.des());
}else{
System.err.println( method.getName() + "没有Info注解" );
}
}
}
}
Java注解模拟实现Junit
- 创建注解类
import java.lang.annotation.*;
@Target(value={ElementType.METHOD}) //目标:作用域方法 //两种写法
@Retention(RetentionPolicy.RUNTIME) //保留范围:运行时保留,不会被jvm丢弃
public @interface Beta {
//这个注解类中不需要任何属性
}
- 编写测试用例类
public class Test {
@Beta //加上自定义的测试注解
public void test(){
System.out.println("SUCCESS!");
}
@Beta
public void test2(){
System.out.println("成功了!哈哈哈...");
}
@Beta
public void test3(){
System.err.println("嘻嘻嘻...");
}
}
- 编写注解方法的操作测试类
public class TestBeta {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
Class clazz = Test.class;
Method[] methods = clazz.getMethods();
if(methods != null){
for(Method method : methods){
boolean isAP = method.isAnnotationPresent(Beta.class);
if(isAP){
method.invoke(clazz.newInstance(), null);
}
}
}
}
}
注解模拟Hibernate中根据实体类在数据库建表的方法
- 创建用来指定表名的注解
import java.lang.annotation.*;
@Target(ElementType.TYPE) //说明作用在类上
@Retention(RetentionPolicy.RUNTIME) //运行时级别
public @interface TableName {
public String name() default "";
}
- 创建用来指定类型的注解
import java.lang.annotation.*;
@Target(ElementType.FIELD) //说明用在属性上
@Retention(RetentionPolicy.RUNTIME)
public @interface Type {
public String type() default "varchar(20)";
public Constraints constraints() default @Constraints;
}
- 创建指定约束的注解
@Target(ElementType.FIELD) //说明在属性上
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
public boolean primaryKey() default false; //是否为主键
public boolean allowNull() default true; //是否可为空
public boolean unique() default false; //是否唯一
public boolean identity() default false; //是否自增
}
- 创建实体类
@TableName
public class StuInfo {
@Type(type="int" ,constraints=@Constraints(primaryKey=true,identity=true))
private int usid;
@Type(type="varchar(200)" ,constraints=@Constraints(allowNull=false,unique=true))
private String sname;
@Type(type="int")
private int age;
@Type(constraints=@Constraints(unique=true))
private String tel;
public int getUsid() {
return usid;
}
public void setUsid(int usid) {
this.usid = usid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
}
- 创建测试类
public class TableCreator {
public static void main(String[] args) {
TableCreator tc = new TableCreator();
tc.run();
}
static{
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void run(){
Connection con = null;
Statement stmt = null;
try {
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test","数据库用户名","密码");
stmt = con.createStatement();
String sql = this.getSql(StuInfo.class);
System.out.println(sql);
stmt.execute(sql); //执行sql
System.out.println("创建成功");
} catch (Exception e) {
System.err.println("创建失败");
e.printStackTrace();
}finally {
try {
if(stmt != null){
stmt.close();
}
if( con != null ){
con.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//建表语句
public String getSql(Class<?> cl){
TableName tn = cl.getAnnotation(TableName.class);
if(tn == null){
return null;
}
String tableName = tn.name();
if( tableName == null || "".equals(tableName) ){
tableName = cl.getSimpleName(); //这里不要使用getName(),那样会返回带有包路径的字符串值
}
//如果需要考虑性能,建议使用StringBuffer
StringBuffer sbf = new StringBuffer();
sbf.append("create table ").append(tableName).append("(");
//拼接列 -> 获取这个对象中的所有属性 -> 判断属性上是否有Type注解
Field[] fields = cl.getDeclaredFields();
if(fields == null || fields.length <= 0){
return null;
}
Type type = null;
for( Field field : fields ){
type = field.getAnnotation(Type.class);
if(type != null){
sbf.append( field.getName() ).append(" ").append( type.type() );
//这个列上的约束
if( type.constraints().primaryKey() ){ //如果是主键
sbf.append(" primary key");
if( type.constraints().identity() ){//则需要判断是否自增
sbf.append(" auto_increment");
}
}else{//不是主键,判断是否可为空,是否唯一
if( !type.constraints().allowNull() ){ //不可为空
sbf.append(" not null");
}
if( type.constraints().unique() ){ //唯一
sbf.append(" unique");
}
}
sbf.append(",");
}
}
String sql = sbf.toString();
//处理最后一个多余的逗号,并加上反括号
sql = sql.substring(0,sql.lastIndexOf(",")) + ")";
return sql;
}
}