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();
}
}
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);
}
}