Java注解

一、注解的基本概念

注解是JDK1.5及以后版本引入的,它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。注解是以‘@注解名’在代码中存在的,它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。(摘自 百度百科
按照运行机制,注解可以分为三类:1、源码注解:即注解只在源代码中存在,在编译成.class文件后就不存在了;2、编译时注解:即在源码和编译的.class文件中都存在,例如常见的JDK 注解@Override、@Deprecated、@SuppressWarings;3、运行时注解:即注解在运行时仍然存在,甚至可能会影响程序的运行逻辑,例如Spring框架中用到的@Autowired注解。
我们也可以按照来源来将注解划分为三类:1、来自JDK的注解,就比如前面提到的@Override、@Deprecated、@SuppressWarings;2、来自第三方框架的注解,例如Spring的@Autowired;3、当然还有我们自己定义的注解。
还有一种特殊的注解,元注解,就是指注解的注解,这在自定义注解时经常使用。

二、自定义注解

我们可以通过自定义注解来实现我们自己想要的功能,下面通过一个简单的例子来讲解一下自定义注解的一些知识,下面的代码是一个简单的自定义注解。
package com.imooc.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {

	String name();
	
	int age() default 18;
	
}
首先我们可以看到,我们是使用@interface关键字定义注解的,其中注解里定义的类似于一个方法的例如String name();其实是注解的成员,注解的成员通常以无参无异常的方式声明的,我们也可以用default关键字为成员指定一个默认值。这里需要注意的是注解的成员的类型是受限的,只能是基本数据类型或者String,Class,Annotation,Enumeration这几种类型,如果一个注解只有一个成员,那么这个成员就必须取名为value(),在使用注解时可以不显式声明成员名称和等于号(=)。注解也可以没有成员,没有成员的注解称为标识注解。
除了注解定义的成员,我们发现在注解定义上面还有几个注解,这些注解就是元注解,下面来简单分析以下这几个元注解:@Target表示定义的注解的作用域,通常作用域有constructor(构造方法声明),field(字段声明),local_variable(局部变量声明),method(方法声明),package(包声明),parameter(参数声明),type(类,接口声明);@Retention表示定义的注解的运行周期,主要包括source:只在源码显示,编译时会丢弃,class:编译时会记录到class中,运行时忽略,runtime:运行时存在,可以通过反射读取;@Inherited表示被注解可以被子类继承;@Documented表示生成JavaDoc文档时会将注解写入文档。
当我们自定义了一个注解后就可以使用这个注解了,使用注解的语法是:@注解名(成员名=成员值,成员名=成员值……)

三、解析注解

在我们自定义了注解之后,可以通过反射获取类、方法或成员上 运行时的注解信息,从而实现动态控制程序运行时逻辑的目的。下面通过一个实例来解析上面的例子中定义的注解。我们先定义一个类,类名为Boy,在这个类上和类的方法上使用注解,代码如下。
package com.imooc.annotation;

@Description(name="A Class boy", age=20)
public class Boy {

	@Override
	@Description(name="A Method boy", age=20)
	public String name() {
		return null;
	}

	@Override
	public int age() {
		return 0;
	}

}
然后我们再写一个解析注解的类TestAnnotation,通过反射来获取注解的信息。
package com.imooc.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class TestAnnotation {

	public static void main(String[] args) {
		//1、获取Class信息
		Class clazz = Boy.class;
		
		//2、通过反射判断类上是否存在注解
		if(clazz.isAnnotationPresent(Description.class)) {
			//3、获取到类上的注解
			Description desc  = (Description) clazz.getAnnotation(Description.class);
			//4、获取类上注解的信息
			System.out.println("name=" + desc.name() + ",age=" + desc.age());
			
			//5、通过反射获取类的方法
			Method[] methods = clazz.getMethods();
			for (Method method : methods) {
				//6、判断方法上是否有注解
				if(method.isAnnotationPresent(Description.class)) {
					//7、获取方法上的注解
					Description methodDesc = method.getAnnotation(Description.class);
					//8、获取方法上注解的信息
					System.out.println("第一种方式获得注解:name=" + methodDesc.name() + ",age=" + methodDesc.age());
				}
				
				//9、获取方法上所有的注解信息
				Annotation[] anns = method.getAnnotations();
				for (Annotation annotation : anns) {
					//10、遍历注解获取对应的注解信息
					if(annotation instanceof Description) {
						Description methodDesc = (Description) annotation;
						System.out.println("第二种方式获得注解:name=" + methodDesc.name() + ",age=" + methodDesc.age());
					}
				}
				
			}
			
		}
	}

}
运行程序,程序执行如下结果,说明我们自定义的注解解析成功了。
name=A Class boy,age=20
第一种方式获得注解:name=A Method boy,age=20
第二种方式获得注解:name=A Method boy,age=20
接下来我们思考一下,定义一个接口Person,然后让Boy实现这个接口,然后在Person上使用注解,代码如下:
package com.imooc.annotation;

@Description(name="A Class boy", age=20)
public interface Person {
	@Description(name="A Method boy", age=20)
	public String name();
	
	public int age();
	
}
package com.imooc.annotation;


public class Boy implements Person {

	@Override
	public String name() {
		return null;
	}

	@Override
	public int age() {
		return 0;
	}

}
这时再运行TestAnnotation,我们发现控制台并没有打印任何输出,这说明@Inherited这个元注解对与接口的implements是不起作用的,那如果我们将接口Person改成抽象类,让Boy继承这个抽象类结果会是怎样呢?
package com.imooc.annotation;

@Description(name="A Class boy", age=20)
public abstract class Person {
	@Description(name="A Method boy", age=20)
	public String name(){
		return null;
	}
	
	public int age(){
		return 0;
	}
	
}
package com.imooc.annotation;


public class Boy extends Person {

	@Override
	public String name() {
		return null;
	}

	@Override
	public int age() {
		return 0;
	}

}
运行程序,控制台打印如下输出。
name=A Class boy,age=20
这说明@Inherited这个元注解对继承extends是起作用的,但是只会继承类上的注解,并不会继承该类方法上的注解。

四、一个简单实例的记录

这里简单记录一个注解实现的实例,主要用于根据数据库表和表中的字段进行组合,自动生成相应的SQL,下面是代码。
package com.imooc.annotation.test;

@Table("user")
public class UserBean {

	@Column("id")
	private int id;
	
	@Column("user_name")
	private String userName;
	
	@Column("nick_name")
	private String nickName;
	
	@Column("age")
	private int age;
	
	@Column("sex")
	private String sex;
	
	@Column("city")
	private String city;
	
	@Column("email")
	private String email;
	
	@Column("phone")
	private String phone;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getNickName() {
		return nickName;
	}

	public void setNickName(String nickName) {
		this.nickName = nickName;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}
}
package com.imooc.annotation.test;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Table {

	String value();
	
}
package com.imooc.annotation.test;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Column {

	String value();
	
}
package com.imooc.annotation.test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class SQLUtil {

	public static void main(String[] args) throws Exception {
		UserBean user = new UserBean();
		user.setId(1);
		user.setUserName("Jack");
		user.setEmail("test@qq.com,test@126.com,test@163.com");
		
		System.out.println(generateSQL(user));
	}
	
	
	public static String generateSQL(Object obj) throws Exception {
		StringBuffer sb = new StringBuffer();
		
		Class clazz = obj.getClass();
		if(clazz.isAnnotationPresent(Table.class)) {
			Table table = (Table) clazz.getAnnotation(Table.class);
			sb.append("select * form ").append(table.value()).append(" where 1=1 ");
			
			Field[] fields = clazz.getDeclaredFields();
			for(Field field : fields) {
				if(field.isAnnotationPresent(Column.class)) {
					Column column = field.getAnnotation(Column.class);
					String columnName = column.value();
					
					String getMethodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
					Method getMethod = clazz.getMethod(getMethodName);
					Object returnValue = getMethod.invoke(obj);
					
					if(returnValue instanceof String) {
						if(returnValue != null) {
							if(((String) returnValue).contains(",")) {
								String[] spiltStrs = ((String) returnValue).split(",");
								sb.append(" and " + columnName + " in(");
								
								for (String spiltStr : spiltStrs) {
									sb.append(" '" + spiltStr + "', ");
								}
								sb.append(") ");
							} else {
								sb.append(" and " + columnName + "='" + returnValue + "' ");
							}
						}
					}
					
					if(returnValue instanceof Integer) {
						if((int)returnValue != 0) {
							sb.append(" and " + columnName + "=" + returnValue + " ");
						}
					}
				}
			}
			
			
		}
			
		return sb.toString();
	}

}











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值