一、初识注解
在项目开发中,注解的使用无处不在。注解的使用简化了代码,减少了程序员的工作量。
注解的分类
- 按照运行机制
- 源码注解(只在源码上存在,编译成class文件后不存在)
- 编译时注解(源码和class文件都存在,JDK自带的注解属于这种)
- 运行时注解(在运行阶段还起作用,甚至会影响程序逻辑例如:自定义的、第3方(spring)的注解基本都是这种)
- 按照来源来分
- JDK自带的注解
- 第3方注解
- 自定义的注解
元注解(注解的注解)
例如:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
下面是自定义了一个注解Retention,上面的3个注解是修饰注解Retention,所以就是元注解
二、使用注解
1.自定义Annotation
/**
* Author:林万新 lwx
* Date: 2017/11/14
* Time: 12:47
*/
@Inherited
@Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Testable {
}
2.使用注解
/**
* Author:林万新 lwx
* Date: 2017/11/14
* Time: 12:49
*/
public class Client {
@Test
public void client(){
new SubClass();
}
}
@Testable
class SuperClass{
}
class SubClass extends SuperClass{
public SubClass(){
for(Annotation annotation :SubClass.class.getAnnotations()){
System.out.println(annotation);
}
}
}
运行结果:
可以看到通过过去注解遍历出修饰SubClass类的注解
3.自定义注解
要求:
根据Annotation是否包含成员变量,可以把Annotation分为两类:
标记Annotation: 没有成员变量的Annotation; 这种Annotation仅利用自身的存在与否来提供信息;
元数据Annotation: 包含成员变量的Annotation; 它们可以接受(和提供)更多的元数据;
定义新注解使用@interface关键字, 其定义过程与定义接口非常类似(见上面的@Testable), 需要注意的是:Annotation的成员变量在Annotation定义中是以无参的方法形式来声明的, 其方法名和返回值类型定义了该成员变量的名字和类型, 而且我们还可以使用default关键字为这个成员变量设定默认值.
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Tag {
String name() default "该叫啥才好呢?";
String description() default "这家伙很懒, 啥也没留下...";
}
4.提取Annotation信息
- 使用Annotation修饰了类/方法/成员变量等之后,这些Annotation不会自己生效,必须由这些注解的开发者提供相应的工具来提取并处理Annotation信息(当然,只有当定义Annotation时使用了@Retention(RetentionPolicy.RUNTIME)修饰,JVM才会在装载class文件时提取保存在class文件中的
- Java使用Annotation接口来代表程序元素前面的注解, 用AnnotatedElement接口代表程序中可以接受注解的程序元素.像Class Constructor Field Method Package这些类都实现了AnnotatedElement接口.
public final
class Class<T> implements java.io.Serializable,
java.lang.reflect.GenericDeclaration,
java.lang.reflect.Type,
java.lang.reflect.AnnotatedElement {
...
}
public interface AnnotatedElement {
/**
* Returns true if an annotation for the specified type
* is present on this element, else false. This method
* is designed primarily for convenient access to marker annotations.
*/
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
/**
* Returns this element's annotation for the specified type if
* such an annotation is present, else null.
*/
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
/**
* Returns all annotations present on this element.
*/
Annotation[] getAnnotations();
/**
* Returns all annotations that are directly present on this
* element. Unlike the other methods in this interface, this method
* ignores inherited annotations. (Returns an array of length zero if
* no annotations are directly present on this element.) The caller of
* this method is free to modify the returned array; it will have no
* effect on the arrays returned to other callers.
*/
Annotation[] getDeclaredAnnotations();
}
这样, 我们只需要获取到Class Method Filed等这些实现了AnnotatedElement接口的类实例, 就可以获取到我们想要的注解信息了.
/**
* Author:林万新 lwx
* Date: 2017/11/14
* Time: 15:46
*/
public class Client1 {
@Test
public void client() throws NoSuchMethodException {
Annotation[] annotations = this.getClass().getMethod("client").getAnnotations();
for(Annotation annotation : annotations){
System.out.println(annotation.annotationType().getName());
}
}
}
运行结果:
可以看到程序正常输出运行了
如果需要获取某个注解中的元数据,则需要强转成所需的注解类型,然后通过注解对象的抽象方法来访问这些元数据:
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Tag {
String name() default "该叫啥才好呢?";
String description() default "这家伙很懒, 啥也没留下...";
}
/**
* Author:林万新 lwx
* Date: 2017/11/14
* Time: 16:09
*/
@Tag(name = "client2")
public class Client2 {
@Test
public void client2(){
Annotation[] annotations = this.getClass().getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof Tag){
Tag tag = (Tag) annotation;
System.out.println("name: " + tag.name());
System.out.println("description: " + tag.description());
}
}
}
}
运行结果:
可以看到捕获到定义到该类上的注解了,而且输出他的元数据
- 例子
1.定义注解
/**
* Author:林万新 lwx
* Date: 2017/12/6
* Time: 10:58
*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Description {
String value();
}
2.使用注解
/**
* Author:林万新 lwx
* Date: 2017/12/6
* Time: 11:01
*/
@Description("this is a class annotation")
public class Person {
@Description("this is a method annnotation")
public void name(){
return;
}
public void name1(){
return;
}
public String name2() {
return null;
}
}
3.解析注解(用到反射的知识)
/**
* Author:林万新 lwx
* Date: 2017/12/6
* Time: 11:03
*/
public class ParseAnn {
/**
* 解析注解
*/
public static void main(String[] args) throws ClassNotFoundException {
//使用类加载器加载类
Class c = Class.forName("zhu_jie.imoocAnnocation.Person");
//找到类上的注解
boolean isExist = c.isAnnotationPresent(Description.class);
if(isExist){
//get到某个具体注解类型实例:与getAnnocations()对比
Description d = (Description) c.getAnnotation(Description.class);
System.out.println(d.value());
}
//找到方法上的注解:也可以返回具体某个方法
Method[] ms = c.getMethods();
for (Method m : ms){
boolean isMExist = m.isAnnotationPresent(Description.class);
if(isMExist){
Description d = m.getAnnotation(Description.class);
System.out.println(d.value());
}
}
//第2中解析方法上的注解
for(Method m : ms){
//获取方法上所有的注解
Annotation[] as = m.getAnnotations();
for (Annotation a : as){
if(a instanceof Description){
Description d = (Description) a;
System.out.println(d.value());
}
}
}
}
}
注解实战
通过注解拼接SQL查询语句
1.Table 注解
/**
* Author:林万新 lwx
* Date: 2017/12/6
* Time: 11:57
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String value();
}
Column注解
/**
* Author:林万新 lwx
* Date: 2017/12/6
* Time: 11:59
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value();
}
2.ORM
/**
* Author:林万新 lwx
* Date: 2017/12/6
* Time: 11:35
* 对应数据库表user表
*/
@Table("user")
public class User {
@Column("id")
private Integer id;
@Column("user_name")
private String userName;
@Column("password")
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
3.解析注解
/**
* Author:林万新 lwx
* Date: 2017/12/6
* Time: 11:42
*/
public class PraseUser {
public String query(User user){
StringBuffer sb = new StringBuffer();
//获取class
Class c= user.getClass();
//得到表名
boolean exists = c.isAnnotationPresent(Table.class);
if(!exists)
return null;
Table table = (Table) c.getAnnotation(Table.class);
String tableName = table.value();
sb.append("SELECT * FROM ").append(tableName).append(" WHERE 1 = 1");
//获取列名字:需要遍历字段:处理注解
Field[] fileds = c.getDeclaredFields();
for(Field field : fileds){
if(field.isAnnotationPresent(Column.class)){
//得到注解实例+得到注解内容
Column column= field.getAnnotation(Column.class);
String columnName = column.value();
//得到字段的值:通过get方法
String fieldName = field.getName();
String getMethodName = "get" + fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
Object fieldValue=null;
try {
Method getMethod = c.getMethod(getMethodName);
fieldValue = getMethod.invoke(user);
} catch (Exception e) {
e.printStackTrace();
}
//继续拼接sql
if(fieldValue!= null){
sb.append(" AND ").append(columnName).append("=");
if(fieldValue instanceof String)
sb.append("'").append(fieldValue).append("'");
else if(fieldValue instanceof Integer)
sb.append(fieldValue);
}
}
}
return sb.toString();
}
}
4.Test测试
/**
* Author:林万新 lwx
* Date: 2017/12/6
* Time: 15:01
*/
public class PraseUserTest {
@Test
public void query() throws Exception {
User user1 = new User();
user1.setId(1);
User user2 = new User();
user2.setUserName("lwx");
user2.setId(4);
PraseUser praseUser = new PraseUser();
String sql1 = praseUser.query(user1);
System.out.println(sql1);
String sql2 = praseUser.query(user2);
System.out.println(sql2);
}
}
运行结果: