Java基础回顾之注解(Annotation)及纯java代码在数据库中创建一个表

Java基础回顾之注解(Annotation)及纯java代码在数据库中创建一个表_第1张图片
在这里插入图片描述

回顾反射
Java基础回顾之注解(Annotation)及纯java代码在数据库中创建一个表_第2张图片

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

你可能感兴趣的:(java,web开发)