JDK1.5新特性之注解
时间:2017-1-2 20:14
——注解的概述
注释是给人看的,而注解是给程序(框架)看的。
在Servlet3.0中可以使用注解来替代配置文件,开发者就不用再写配置文件了,而是写注解,然后Tomcat来读取注解。
注解也是类,需要定义了才能使用。
在Servlet3.0中又一个注解类是@WebServlet,然后我们就可以在Servlet中使用@WebServlet这个注解了,这个朱姐就是用来替代<servlet>,然后Tomcat会通过反射来读取注解中的信息。
——Java中的注解
* @Overrid:作用在方法上的注解,当方法不是重写父类的方法时会报错。
* @Deprecated:作用在方法上,标记该方法为作废方法(已过时)。
* @SuppressWarnings:作用在方法上,压制警告。
* @Deprecated:作用在方法上,标记该方法为作废方法(已过时)。
* @SuppressWarnings:作用在方法上,压制警告。
——定义注解类
定义注解类不能使用class、enum和interface,而是使用@interface
> public @interface MyAnn{ }
——使用注解目标
所有注解都是Annotation的子类。
注解可以作用在:类(接口或枚举)、属性、方法、构造器、包、参数、局部变量
* 定义注解类:框架的工作
* 使用注解:我们的工作
* 读取注解(反射):框架的工作
定义注解类不能使用class、enum和interface,而是使用@interface
> public @interface MyAnn{ }
——使用注解目标
所有注解都是Annotation的子类。
注解可以作用在:类(接口或枚举)、属性、方法、构造器、包、参数、局部变量
* 定义注解类:框架的工作
* 使用注解:我们的工作
* 读取注解(反射):框架的工作
——注解的定义
* 定义属性
> 格式:类型 属性名()
* 使用注解时给属性赋值
> @MyAnno(name="zhangsan", age=20)
* 注解属性的默认值
> int age() default 100;
> 在使用注解时,可以不给带有默认值的属性赋值。
* 名为value的属性的特权
> 在使用注解时,如果只给名为value的属性赋值,那么可以不给出属性的名称而直接赋值,当存在其他属性时,必须加上“value=”。
> @MyAnno("zhangsan"):表示给value="zhangsan"赋值。
* 注解属性的类型
> 8种基本类型
> String类型
> 枚举类型
> Class类型
> 注解类型
> 以上类型的一维数组类型
> 定义:
@MyAnno1{
int a();
String b();
MyEnum c();
Class d();
MyAnno2 e();
String f();
}
> 使用:
@MyAnno1(
a=100,
b="zhangsan",
c=MyEnum.option,
d=String.class,
e=@MyAnno2(age=20,name="zhangsan"),
f={"123", "456"}
)
——注解的作用目标限定以及保存策略限定
1、目标限定
让一个注解的作用目标只能在类上,而不能在方法上,这就叫作用目标的限定。
在定义注解时,给注解添加注解,这个注解时@Target
Target注解有一个属性:ElementType[] value(),这个属性是一个枚举类型。
使用方法:
@Target(value={ElementType.TYPE, ElementType.METHOD, ElementType/FIELD})
@interface MyAnno{ }
2、保留策略
* 源代码文件(SOURCE)
> 注解只在源代码中存在,当编译时就被忽略了(不能被反射)
* 字节码文件(CLASS)
> 注解在源代码中存在,编译时会把注解信息放到class文件中,但JVM在加载类时,会忽略注解。
* JVM中(RUNTIME)
> 注解在源代码、字节码文件中存在,并且在JVM加载类时,会把注解加载到JVM内存中(它是唯一可以反射的注解)
限定注解的保留策略:
使用RetentionPolicy注解:
@Retention(RetentionPolicy.RUNTIME)
——读取注解(反射)
1、要求:
注解的保留策略必须是RUNTIME
2、反射注解需要从作用目标上反射
* 类上的注解,需要使用Class来获取
* 方法上的注解,需要用Method来返回
* 构造器上的注解,需要用Constructor来获取
* 定义属性
> 格式:类型 属性名()
@interface MyAnno1{
String name();
int age();
}
* 使用注解时给属性赋值
> @MyAnno(name="zhangsan", age=20)
* 注解属性的默认值
> int age() default 100;
> 在使用注解时,可以不给带有默认值的属性赋值。
* 名为value的属性的特权
> 在使用注解时,如果只给名为value的属性赋值,那么可以不给出属性的名称而直接赋值,当存在其他属性时,必须加上“value=”。
> @MyAnno("zhangsan"):表示给value="zhangsan"赋值。
* 注解属性的类型
> 8种基本类型
> String类型
> 枚举类型
> Class类型
> 注解类型
> 以上类型的一维数组类型
> 定义:
@MyAnno1{
int a();
String b();
MyEnum c();
Class d();
MyAnno2 e();
String f();
}
> 使用:
@MyAnno1(
a=100,
b="zhangsan",
c=MyEnum.option,
d=String.class,
e=@MyAnno2(age=20,name="zhangsan"),
f={"123", "456"}
)
——注解的作用目标限定以及保存策略限定
1、目标限定
让一个注解的作用目标只能在类上,而不能在方法上,这就叫作用目标的限定。
在定义注解时,给注解添加注解,这个注解时@Target
Target注解有一个属性:ElementType[] value(),这个属性是一个枚举类型。
使用方法:
@Target(value={ElementType.TYPE, ElementType.METHOD, ElementType/FIELD})
@interface MyAnno{ }
2、保留策略
* 源代码文件(SOURCE)
> 注解只在源代码中存在,当编译时就被忽略了(不能被反射)
* 字节码文件(CLASS)
> 注解在源代码中存在,编译时会把注解信息放到class文件中,但JVM在加载类时,会忽略注解。
* JVM中(RUNTIME)
> 注解在源代码、字节码文件中存在,并且在JVM加载类时,会把注解加载到JVM内存中(它是唯一可以反射的注解)
限定注解的保留策略:
使用RetentionPolicy注解:
@Retention(RetentionPolicy.RUNTIME)
——读取注解(反射)
1、要求:
注解的保留策略必须是RUNTIME
2、反射注解需要从作用目标上反射
* 类上的注解,需要使用Class来获取
* 方法上的注解,需要用Method来返回
* 构造器上的注解,需要用Constructor来获取
* 成员上的注解,需要用Field来获取
Class类方法概要:
<T extends Annotation> getAnnotation(Class<A> annotationClass)
如果存在该元素的指定类型的注解,则返回这些注解,否则返回null。
Annotation[] getAnnotations()
返回此元素上存在的所有注解。
Method、Field、Constructor:
这三个类都是AccessibleObject的子类。
AccessibleObject类方法概要:
<T extends Annotation> getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注解,则返回这些注解,否则返回null。
Annotation[] getAnnotations()
返回此元素上存在的所有注解。
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注解。
Class类方法概要:
<T extends Annotation> getAnnotation(Class<A> annotationClass)
如果存在该元素的指定类型的注解,则返回这些注解,否则返回null。
Annotation[] getAnnotations()
返回此元素上存在的所有注解。
Method、Field、Constructor:
这三个类都是AccessibleObject的子类。
AccessibleObject类方法概要:
<T extends Annotation> getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注解,则返回这些注解,否则返回null。
Annotation[] getAnnotations()
返回此元素上存在的所有注解。
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注解。
示例代码:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import org.junit.Test;
public class Demo {
@Test
public void fun1() {
/*
* 1、得到作用目标
*/
Class<A> c = A.class;
/*
* 2、获取指定类型的注解
*/
MyAnno1 myAnno1 = c.getAnnotation(MyAnno1.class);
System.out.println(myAnno1.name() + ", " + myAnno1.age());
}
@Test
public void fun2() throws Exception {
/*
* 1、得到作用目标
*/
Class<A> c = A.class;
// Field权限必须为public
Field field = c.getField("name");
/*
* 2、获取指定类型的注解
*/
MyAnno1 myAnno1 = field.getAnnotation(MyAnno1.class);
System.out.println(myAnno1.name() + ", " + myAnno1.age());
}
}
@MyAnno1(name = "zhangsan", age = 20)
class A {
@MyAnno1(name = "lisi", age = 21)
public String name;
}
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno1 {
String name();
int age();
}
——反射泛型信息
public Type getGenericSuperclass()
返回表示此Class所表示的实体(类、接口、基本类型或void)的直接父类的Type。
获取传递给父类的泛型信息。
返回的类型是Type接口的子接口:ParameterizedType(参数化类型) == A<String>
public Type getGenericSuperclass()
返回表示此Class所表示的实体(类、接口、基本类型或void)的直接父类的Type。
获取传递给父类的泛型信息。
返回的类型是Type接口的子接口:ParameterizedType(参数化类型) == A<String>
1、子类:得到当前类的Class对象:this.getClass()
2、Class:得到当前类父类的参数化类型(A<String, Integer...>):Type getGenericSuperclass(),因为返回值是ParameterizedType,所以需要强制类型转换。
3、ParameterizedType:得到所有的类型参数<String, Integer...>:Type[] getActualTypeArguments()
示例代码:
System.out.println(c3);
}
package demo2;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.junit.Test;
public class Demo1 {
@Test
public void fun() {
new B();
new C();
}
}
abstract class A<T> {
public A() {
/*
* 在这里获取子类传递的泛型信息,得到一个Class对象
*/
Class c = this.getClass(); // 得到子类的类型
// 得到的type就是A<String>
Type type = c.getGenericSuperclass();
// 因为type的类型是ParameterizedType,所以需要强转
ParameterizedType pType = (ParameterizedType) type;
// 获取类参数,得到的是一个数组<String, Integer...>
Type[] types = pType.getActualTypeArguments();
// 得到String
Class c2 = (Class) types[0];
System.out.println(c2); // String或者Integer
// 简写
Class c3 = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
System.out.println(c3);
}
}
class B extends A<String> {
}
class C extends A<Integer> {
——反射泛型和反射注解的应用案例
User类:
package demo2;
@Table("tb_user") // 它的值表示当前类所对应的表
public class User {
@ID("u_id") // 表示当前属性对应的列名,而且说明这个字段是主键字段
private String uid;
@Column("username")
private String username;
@Column("password")
private String password;
}
@Test
public void fun(){
Class<User> c = User.class;
Table a = c.getAnnotation(Table.class);
System.out.println(a.value());
Field f = c.getDeclaredField("uid");
f.setAccessible(true);
ID id = f.getAnnotation(ID.class);
System.out.println(id.value());
}
----------------------------------------------------------------------------------------------------------------------------
Table注解:
package demo2;
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String value();
}
----------------------------------------------------------------------------------------------------------------------------
ID注解:
package demo2;
@Retention(RetentionPolicy.RUNTIME)
public @interface ID {
String value();
}
----------------------------------------------------------------------------------------------------------------------------
Column注解:
package demo2;
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value();
}
----------------------------------------------------------------------------------------------------------------------------
BaseDAO:
package demo2;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.List;
-------------------------
public class Demo2 {
private QueryRunner qr = new TxQueryRunner();
/*
* 使用dbutils
*/
public void addUser(User user) {
String sql = "";
Object[] params = {};
qr.update(sql, params);
}
public void addCustomer(Customer customer) {
String sql = "";
Object[] params;
qr.update(sql, params);
}
}
-------------------------
/**
* 因为普通DAO有许多重复的工作
* 所以可以考虑编写一个BaseDAO来完成重复操作
* 功能与BaseServlet相似。
* @author WYC
*
* @param <T>
*/
class BaseDAO<T> {
private QueryRunner qr = new TxQueryRunner();
private Class<T> beanClass;
private int length;
public BaseDAO() {
// 获取泛型参数,用于获得表名
this.beanClass = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
// 获取属性个数,用于获得参数个数、参数值、参数列名
Field[] fields = beanClass.getDeclaredFields();
this.length = fields.length;
}
public void add(T bean) {
// 可以将表名作为注解配置到类上,然后通过反射注解来获取配置的表名信息
// 可以将表名作为注解配置到类上,然后通过反射注解来获取配置的表名信息
String sql = "insert into " + beanClass.getSimpleName() + " values(";
// 指定参数个数
for (int i = 0; i < this.length; i++) {
if (i == length - 1) {
sql += "?)";
} else {
sql += "?,";
}
}
// 可以通过反射Field来获取参数值
Object[] params = {/* 参数值是什么 */};
qr.update(sql, params);
}
public void update(T bean) {
}
public void delete(String uuid) {
}
public T load(String uuid) {
return null;
}
public List<T> findAll() {
return null;
}
}
-------------------------
class UserDAO extends BaseDAO<User> {
public void addUser(User user) {
super.add(user);
}
}