Java基础知识之注解(Annotation)及纯java代码在数据库中创建一个表
程序员文章站
2022-04-16 16:32:55
package com.powernode.annotation.test1;public class Person {private String name ="张三";private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;...
回顾反射
package com.powernode.annotation.test1; public class Person { private String name ="张三"; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } ////////////////////////////////////////////////////////////////////////////////// // 当子类继承下来的方法不再适合子类的需要的时候,则需要在子类中对该方法重新定义,称为方法重新,也称为方法覆盖 // 方法覆盖的要求(面试的时候肯定会遇到) // 1.访问权限不能降低 // 2.返回类型必须相同 // 3.方法名称必须相同 // 4.参数列表必须相同 // 4.抛出的异常不能扩大 ///////////////////////////////////////////////////////////////////////////////// // @Override 这就是一个注解,这个注解的作用是告诉编译器,我们就是要执行方法覆盖,则编译器会按照方法覆盖的要求进行检查 // 所以,我们在执行方法覆盖的时候,为了避免错误,在覆盖的方法上面加上@Override,检查覆盖是否成功 @Override public String toString() { return "Person[name=" + name + ",age=" + age + "]"; } public Person() { super(); } public Person(String name, int age) { super(); this.name = name; this.age = age; } }
package com.powernode.annotation.test1; public class Main { public static void main(String[] args) { Person per = new Person("张三", 23); System.out.println(per); System.out.println(per.toString()); } }
package com.powernode.annotation.test2; public class Person { public void test1() { System.out.println("Person类中正常的test1()方法被调用"); } // 在一个类中,由于某种原因某个方法已经不再推荐使用,但是暂时又没有提供新的替代方案 // 可以给方法上面加上一个注解@Deprecated,表示这个方法过时了,最好别用了 // 这样编译器会在方法名称上面加上删除线,调用该方法的时候也会被加上删除线 // 过时的方法最好不要调用了,从语法上,也是可以调用的 @Deprecated public void test2() { System.out.println("Person类中过时的test1()方法被调用"); } }
package com.powernode.annotation.test2; public class Main { public static void main(String[] args) { Person per = new Person(); per.test1(); per.test2(); } }
package com.powernode.annotation.test3; import java.util.*; public class CollectionTest { public static void main(String[] args) { // 我们使用集合的时候应该指定集合的泛型类型,如果没有指定泛型,则编译器会产生警告信息 // 警告信息不回影响程序的执行,但是影响代码的美观 // 我们可以使用注解,然编译器忽略这些警告信息 // ====================================================================================== // 让编译器忽略泛型的警告 // @SuppressWarnings({"rawtypes"}) // ====================================================================================== // 可以让编译器同时忽略多个讲过:忽略泛型的警告;忽略从未使用的局部变量警告 ;注意:忽略的警告的类型都是预先定义好的 // @SuppressWarnings({ "rawtypes", "unused" }) // ====================================================================================== // 上面的代码也可以写成如下的形式 @SuppressWarnings(value = { "rawtypes", "unused" }) Collection coll = new ArrayList(); // 在Java中,{} 表示静态初始化数组对象 String[] arr = { "Hello", "World", "Java" }; } }
package com.powernode.annotation.test4; /////////////////////////////////////////////////////////////////////////// // 注解是从JKD1.5开始出现的, // 自定义注解实际上就是一种类型而已,也就是引用类型(Java中除了8种基本类型之外,我们见到的任何类型都是引用类型) // 类型的作用:(1)声明变量;(2)声明方法的参数;(3)声明方法的返回类型;(4)强制类型转换 ///////////////////////////////////////////////////////////////////////////// // 自定义注解的开发过程 // 1.声明一个类MyAnnotation // 2.把class关键字改成@interface // 这样我们就声明了一个自定义的注解;当我们用@interface声明一个注解时候,实际上是声明了一个接口,这个接口自动的继承 // 了 java.lang.annotation.Annotation接口.但是我们只需要使用@interface这个关键字来声明注解 // 编译器会自动的完成相关的操作,不需要我们手动的指明继承Annotation接口 /////////////////////////////////////////////////////////////////////////// // 我们声明注解的目的是:为了在其他的类中来使用这个注解(使用注解来携带信息) // 这个注解可以在其他的类型的任何位置进行使用, // 例如:从某些方面看,annotation就像修饰符一样被使用,并应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中。 public @interface MyAnnotation { }
package com.powernode.annotation.test4; // 我们声明注解的目的是:为了在其他的类中来使用这个注解(使用注解来携带信息) // 这个注解可以在其他的类型的任何位置进行使用, // 例如:从某些方面看,annotation就像修饰符一样被使用,并应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中。 @MyAnnotation public class Main { @MyAnnotation private String str; @MyAnnotation public static void main(String[] args) { @MyAnnotation
String str2 = "Hello"; } }
package com.powernode.annotation.test5; // 我们可以在注解中声明属性.(在注解中通过属性来携带信息) public @interface MyAnnotation { // 注解中声明属性的语法比较怪异,即像在Java类中声明属性,又像在Java类中声明方法(实际上:即是声明了属性,又是声明了方法) // 注解中声明属性的规范: 属性类型 属性名称 (); // 属性名称的规范:名词或名词性短语,第一个单词首字符小写,其余单词首字符大写 int age(); String name(); String schoolName(); }
package com.powernode.annotation.test5; // 在使用注解的时候,通过主键中的属性来携带信息 // 因为我们在注解中声明了属性,所以在使用注解的时候必须要指明属性值,多个属性之间没有顺序,多个属性之间通过逗号分隔 @MyAnnotation(name = "张三", age = 23, schoolName = "动力节点") public class Main { @MyAnnotation(age = 23, name = "张三", schoolName = "动力节点") public static void main(String[] args) { } }
package com.powernode.annotation.test6; // 我们可以在注解中声明属性.(在注解中通过属性来携带信息) public @interface MyAnnotation { // 注解中声明属性的语法比较怪异,即像在Java类中声明属性,又像在Java类中声明方法(实际上:即是声明了属性,又是声明了方法) // 注解中声明属性的规范: 属性类型 属性名称 (); // 属性名称的规范:名词或名词性短语,第一个单词首字符小写,其余单词首字符大写 int age(); String name(); // 可以给注解中的属性提供缺省值 String schoolName() default "动力节点"; int [] arr() ; }
package com.powernode.annotation.test6; // 在使用注解的时候,通过主键中的属性来携带信息 // 因为我们在注解中声明了属性,所以在使用注解的时候必须要指明属性值,多个属性之间没有顺序,多个属性之间通过逗号分隔 // @MyAnnotation这个注解中的schoolName属性有缺省值,所以在使用注解的时候,我们可以不用指明schoolName的属性值 // schoolName属性的值就是缺省值,也就是"动力节点" @MyAnnotation(name = "张三", age = 23, arr = { 1, 2, 3 }) public class Main { // 当然,提供了缺省值的属性也可以指定为其他的值 @MyAnnotation(age = 23, name = "张三", schoolName = "动力节点-北京北部校区", arr = { 4, 5, 6 }) public static void main(String[] args) { } }
package com.powernode.annotation.test7; public @interface MyAnnotation { String[] value(); }
package com.powernode.annotation.test7; // 如果注解中只有一个属性,并且属性名称是value,这样的话我们使用注解的时候,可以指明属性名称,也可以忽略属性名称 @MyAnnotation(value = { "Hello", "World" }) public class Main { @MyAnnotation({ "Hello", "World" }) public static void main(String[] args) { } }
元注解
package com.powernode.annotation.test8; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //====================================================================================================== // 我们声明的主键通常可以在类的任何位置进行使用 // 从某些方面看,annotation就像修饰符一样被使用,并应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中使用注解。 // 但是在实际开发的时候 ,注解通常会出现在特定的位置,我们如何限定自定义注解的使用范围呢? 我们可以使用元注解 // 什么是元注解呢?也就是注解的主键,专门对自定义注解进行说明的;元注解是JKD自带的,JKD自带多种元注解 // ====================================================================================================== // 我们如何限定自定义注解的使用范围呢? 我们可以使用@Target元注解 // @Target说明了Annotation所修饰的对象范围:即注解的作用域,用于说明注解的使用范围(即注解可以用在什么地方,比如类的注解,方法注解,成员变量注解等等) // 注意:如果Target元注解没有出现,那么定义的注解可以应用于程序的任何元素。 // @Target取值是在java.lang.annotation.ElementType这个枚举中规定的: //1.CONSTRUCTOR:用于描述构造器 //2.FIELD:用于描述域 //3.LOCAL_VARIABLE:用于描述局部变量 //4.METHOD:用于描述方法 //5.PACKAGE:用于描述包 //6.PARAMETER:用于描述参数 //7.TYPE:用于描述类、接口(包括注解类型) 或enum声明 // 选择注解的使用范围的是,可以同时选择多个使用范围(注解中的属性就是一个ElementType []) // ====================================================================================================== // @Retention定义了该Annotation被保留的时间长短: // (1)某些Annotation仅出现在源代码中,而被编译器丢弃; // (2)而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,运行时被忽略 // (3)而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。 // 使用这个meta-Annotation可以对 Annotation的“生命周期”限制。 // @Retention的取值是在RetentionPoicy这个枚举中规定的 // 1.SOURCE:在源文件中有效(即源文件保留) // 2.CLASS:在class文件中有效(即class保留) // 3.RUNTIME:在运行时有效(即运行时保留,注意:只有注解信息在运行时保留,我们才能在运行时通过反射读取到注解信息) // 注解的保留范围,只能三选一 ///////////////////////////////////////////////////////////////////////////////////////////////////////// //@Target({ ElementType.TYPE }) // 规定了自定义注解的使用范围是:只能在类型上面使用 @Target({ ElementType.TYPE, ElementType.METHOD }) // 规定了自定义注解的使用范围是:可以在类型上面使用,也可以在方法上面使用 @Retention(RetentionPolicy.CLASS) // 注解信息在运行时保留 public @interface MyAnnotation { int age(); String name(); String schoolName() default "动力节点"; }
package com.powernode.annotation.test8; @MyAnnotation(name = "张三", age = 23, schoolName = "动力节点") public class Main { @MyAnnotation(name = "张三", age = 23, schoolName = "动力节点") public static void main(String[] args) { } }
注解作用域
package com.powernode.annotation.test9; import java.lang.annotation.*; @Target({ ElementType.TYPE }) // 注解在类型上面使用 @Retention(RetentionPolicy.RUNTIME) // 注解在运行时保留 @Inherited // 父类中使用的注解可以被子类继承 public @interface MyAnnotation1 { }
package com.powernode.annotation.test9; import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation2 { }
package com.powernode.annotation.test9; // 声明一个子类,继承基类.在子类中使用@MyAnnotation2 @MyAnnotation2 public class SubClass extends SuperClass { }
package com.powernode.annotation.test9; // 定义一个基类,在基类中使用@MyAnnotation1 @MyAnnotation1 public class SuperClass { }
package com.powernode.annotation.test9; import java.lang.annotation.Annotation; public class Main { // 通过反射操作获取类中携带的注解信息 public static void reflectTest() { // 获取SubClass对应的Class对象 Class claz = SubClass.class; // 通过Class对象获取类中携带的注解. // 在一个类中可以携带多个注解,claz.getAnnotations()返回的是一个注解的数组 Annotation[] annos = claz.getAnnotations(); System.out.println("数组中长度是:" + annos.length); // 变量数组 for (Annotation anno : annos) { System.out.println(anno); } } public static void main(String[] args) { reflectTest(); } }
others
package com.powernode.annotation.test9.others; import java.lang.annotation.*; @Target({ ElementType.TYPE }) // 注解在类型上面使用 @Retention(RetentionPolicy.CLASS) // 注解在字节码中保留,在运行时被忽略 @Inherited // 父类中使用的注解可以被子类继承 public @interface MyAnnotation1 { }
package com.powernode.annotation.test9.others; import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation2 { }
package com.powernode.annotation.test9.others; // 声明一个子类,继承基类.在子类中使用@MyAnnotation2 @MyAnnotation2 public class SubClass extends SuperClass { }
package com.powernode.annotation.test9.others; // 定义一个基类,在基类中使用@MyAnnotation1 @MyAnnotation1 public class SuperClass { }
package com.powernode.annotation.test9.others; import java.lang.annotation.Annotation; public class Main { // 通过反射操作获取类中携带的注解信息 public static void reflectTest() { // 获取SubClass对应的Class对象 Class claz = SubClass.class; // 通过Class对象获取类中携带的注解. // 在一个类中可以携带多个注解,claz.getAnnotations()返回的是一个注解的数组 Annotation[] annos = claz.getAnnotations(); System.out.println("数组中长度是:" + annos.length); // 变量数组 for (Annotation anno : annos) { System.out.println(anno); } } /**
*
* @param args
*/ public static void main(String[] args) { reflectTest(); } }
注解与反射的应用
注解在实际开发中的作用(可以根据下面代码+jdbc连接数据库,就可以实现纯java代码在数据库中创建一个表。hibenate框架是不是这样设计的?(Hibernate采用XML来对对象关系映射进行配置,不依赖于任何代码,只需修改XML配置文件即可)。;权限控制是不是也是这样实现的?待考察。。。)
使用注解在类中携带信息,程序运行的时候通过反射操作获取到注解信息,然后根据获取到的信息生成数据库的建表语句
程序中携带信息的方式
1.通过注解来携带信息,然后通过反射来读取信息
2.通过文件来携带信息,然后通过IO来读取信息
package com.powernode.annotation.test10; import java.lang.annotation.*; @Target({ ElementType.TYPE }) // 在类型上面使用注解 @Retention(RetentionPolicy.RUNTIME) // 在运行时保留注解信息 public @interface Table { // 在注解中通过定义属性来携带信息 String tableName(); // 携带表名信息的属性 }
package com.powernode.annotation.test10; import java.io.Serializable; import java.sql.Date; /*
现实中的一个实体对应着一个数据库表;一个数据库表会对应着一个Java类;
实体中的属性成为表中的字段;表中的字段对应着类中的属性
和数据库表对应着的类称为JavaBean类,JavaBean的规范
1.类中的属性私有化,并且提供公开的getter/settter()方法
2.类中覆盖toString()方法 (为了输出对象做好了准备)
3.类中覆盖hashCode()/equals()方法(覆盖hashCode()/equals()的目的是为了把JavaBean类的对象放到HashMap/HashSet中做好准备)
4.类中提供公开的无参数的构造方法
5.该类要实现Serialiazble接口,并且声明serialVersionUID(使用Eclipse工具生成的) 为序列化做好了准备
我们要执行的功能,根据一个写好的JavaBean类,自动的生成数据库的建表语句(DDL)
创建数据库表所需要的信息:
(1)表名信息
(2)字段的信息,包括 字段名称,字段类型,字段长度,字段约束
我们如何来携带上面的建表所需要的信息呢?使用注解!
1.为了在JavaBean类中携带表名信息,我们创建一个@Table的注解,这个注解在类型上面使用,因为一个JavaBean类对应一个表
2.为了在JavaBean类中携带字段信息,我们创建一个@Column的注解,这个注解在类的属性中使用;因为类的属性对应着表中的字段
注解在实际开发中的作用
使用注解在类中携带信息,程序运行的时候通过反射操作获取到注解信息,然后根据获取到的信息生成数据库的建表语句
程序中携带信息的方式
1.通过注解来携带信息,然后通过反射来读取信息
2.通过文件来携带信息,然后通过IO来读取信息
*/ @Table(tableName = "EMP") public class Emp implements Serializable { private static final long serialVersionUID = -7125973271283015196L; @Column(columnName = "EMPNO", columnType = "INT", columnLength = 4, columnConstraint = "PRIMARY KEY") private int empno; @Column(columnName = "ENAME", columnType = "VARCHAR", columnLength = 10) private String ename; @Column(columnName = "JOB", columnType = "VARCHAR", columnLength = 10) private String job; @Column(columnName = "HIREDATE", columnType = "DATE") private java.sql.Date hiredate; public int getEmpno() { return empno; } public void setEmpno(int empno) { this.empno = empno; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public java.sql.Date getHiredate() { return hiredate; } public void setHiredate(java.sql.Date hiredate) { this.hiredate = hiredate; } @Override public String toString() { return "Emp [empno=" + empno + ", ename=" + ename + ", job=" + job + ", hiredate=" + hiredate + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + empno; result = prime * result + ((ename == null) ? 0 : ename.hashCode()); result = prime * result + ((hiredate == null) ? 0 : hiredate.hashCode()); result = prime * result + ((job == null) ? 0 : job.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Emp other = (Emp) obj; if (empno != other.empno) return false; if (ename == null) { if (other.ename != null) return false; } else if (!ename.equals(other.ename)) return false; if (hiredate == null) { if (other.hiredate != null) return false; } else if (!hiredate.equals(other.hiredate)) return false; if (job == null) { if (other.job != null) return false; } else if (!job.equals(other.job)) return false; return true; } public Emp() { super(); } public Emp(int empno, String ename, String job, Date hiredate) { super(); this.empno = empno; this.ename = ename; this.job = job; this.hiredate = hiredate; } }
package com.powernode.annotation.test10; import java.lang.annotation.*; @Target({ ElementType.FIELD }) // 在类的属性中使用该注解 @Retention(RetentionPolicy.RUNTIME) // 字段的信息,包括 字段名称,字段类型,字段长度,字段约束 public @interface Column { String columnName(); // 字段名称 String columnType(); // 字段类型 int columnLength() default 10; // 字段长度 String columnConstraint() default ""; // 字段约束 }
package com.powernode.annotation.test10; import java.lang.reflect.Field; public class ReflectTest { /**
* 通过反射操作,获取类中携带的注解信息.根据读取到的信息生成数据库的建表语句
*
* @return
*/ public static String buildSql() { // 准备数据库的建表语句 StringBuilder str = new StringBuilder("CREATE TABLE "); // 获取Emp类对应的Class对象 Class claz = Emp.class; // ============================================================= // 一.获取Emp类中携带的@Table注解,以此来获取表名信息 // (1)获取Emp类中携带的Table注解 Table table = (Table) claz.getAnnotation(Table.class); // (2)获取Table注解中的的属性信息 String tableName = table.tableName();// 获取表名信息 // (3)把表名信息拼接到SQL语句中 str.append(tableName + " ("); // ============================================================= // 二:获取Emp类中携带的Column注解,来获取字段的相关信息 // (1)获取类中声明的所有的属性 Field[] fields = claz.getDeclaredFields(); // (2)遍历保存所有属性的Field的数组,取出每个属性 for (Field field : fields) { // (3)判断属性中是否使用了Column注解 if (field.isAnnotationPresent(Column.class)) { // (4)获取属性中使用的Column注解 Column column = field.getAnnotation(Column.class); // (5)获取注解中携带的字段信息 String columnName = column.columnName(); // 获取字段名信息 String columnType = column.columnType(); // 获取字段类型信息 int columnLength = column.columnLength(); // 获取字段长度信息 String columnConstraint = column.columnConstraint(); // 获取字段约束信息 // (6)把字段的相关信息拼接到SQL语句中 if (columnName.equalsIgnoreCase("hiredate")) { str.append(columnName + " " + columnType + " " + columnConstraint + ","); } else { str.append(columnName + " " + columnType + " (" + columnLength + ") " + columnConstraint + ","); } } } // 去除SQL中最末尾的逗号,并且关闭SQL语句中的() String sql = str.substring(0, str.length() - 1) + ")"; return sql; } public static void main(String[] args) { String sql = buildSql(); System.out.println(sql); } }
本文地址:https://blog.csdn.net/qq_30347133/article/details/107699128