学习Java注解及简单应用栗子

学习java注解能帮助我们读懂别人的代码,特别是框架方面的代码。还能让编程更加简洁,代码更加清晰。

"注解"是JDK1.5引入的,Java提供了一种原程序中的元素关联任何信息和任何元数据的途径和方法。





Java中的常见注解

JDK自带注解:

@override                 表明这个方法是覆盖了父类的或实现的接口的一个方法

@Deprecated            表明这个方法过时了

@Suppvisewarnings   忽略过时警告



常见第三方注解

有Spring的@Autowired、@Service、@Repository
Mybatis的@InsertProvider、@UpdateProvider、@Options


注解分类

按照运行机制分:
1.源码注解                                                      注解只在源码中存在,编译成.class文件就不存在了
2.编译注解 注解在源码和.class文件中都存在,比如前面的@override、@Deprecated、@Suppvisewarnings
3.运行时注解 在运行阶段还起作用,甚至会影响运行逻辑的注解,比如前面的@Autowired
4.元注解 注解的注解





自定义注解

@Target({ElementType.METHOD,ElementType.TYPE}) //作用域
@Retention(RetentionPolicy.RUNTIME)           //生命周期
@Inherited
@Documented                          //以上为元注解
public @interface Description {      //使用@interface关键字定义注解
	String value();     //成员以无参数无异常方式声明
	//String author();
	//int age() default 18;     //用default为成员指定一个默认值
	//成员类型是受限的,合法的类型包括基本类型及String,Class,Annotation,Enumeration
	
}

Tips: 如果注解只有一个成员,则成员名必须取名为value(),使用时可以忽略成员名和赋值号(=)
          注解类可以没有成员,没有成员的注解称为标识注解
注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。


元注解

元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
    1.@Target,
    2.@Retention,
    3.@Documented,
    4.@Inherited
  这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。


@Target:

   @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

  作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

  取值(ElementType)有:

    1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

使用实例:
@Target(ElementType.TYPE)
public @interface Table {
    /**
     * 数据表名称注解,默认值为类名称
     * @return
     */
    public String tableName() default "className";
}

@Target(ElementType.FIELD)
public @interface NoDBColumn {

}
注解Table 可以用于注解类、接口(包括注解类型) 或enum声明,而注解NoDBColumn仅可用于注解类的成员变量。




@Retention:

  @Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

  作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

  取值(RetentionPoicy)有:

    1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在运行时有效(即运行时保留)

  Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。具体实例如下:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    public String name() default "fieldName";
    public String setFuncName() default "setField";
    public String getFuncName() default "getField"; 
    public boolean defaultDBValue() default false;
}
Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理




@Documented:

  @Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。





@Inherited:

  @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

  注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

  当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

  实例代码:

@Inherited
public @interface Greeting {
    public enum FontColor{ BULE,RED,GREEN};
    String name();
    FontColor fontColor() default FontColor.GREEN;
}




解析注解

概念:通过反射获取类、函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑

Child类:

@Description("I am class annotation")
public class Child implements Person {

	@Override
	@Description("I am method annotation")
	public String name() {
		return null;
	}

}

解析注解类:

public class parseAnn {
	public static void main(String[] args){
		
		try {
			//1.使用类加载器加载类
			Class cs=Class.forName("com.ann.test.Child");
			//2.找到类上面的注解
			boolean isExist=cs.isAnnotationPresent(Description.class);
			if(isExist){
				//3.拿到注解实例
				Description d=(Description) cs.getAnnotation(Description.class);
				System.out.println(d.value());
			}
			//4.找到方法上的注解
			Method[] ms=cs.getMethods();
			for(Method m:ms){
				boolean isMExist=m.isAnnotationPresent(Description.class);
				if(isMExist){
					Description d=(Description) m.getAnnotation(Description.class);
					System.out.println(d.value());
				}
			}
			//另一种解析方法
			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());
					}
				}
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}
运行结果:

I am class annotation
I am method annotation
I am method annotation





下面举个例子来模拟简单使用"注解"解决的持久层框架

Column注解:
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
	String value();
}


Table注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
	String value();
}


Filter类:

@Table("user")
public class Filter {
	@Column("id")
	private int id;
	@Column("user_name")
	private String userName;
	@Column("nick_name")
	private String nickName;
	@Column("age")
	private int age;
	@Column("city")
	private String city;
	@Column("email")
	private String email;
	@Column("mobile")
	private String mobile;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}	
	.............................
	.........................

}


测试类:

public class Test {
	
	public static String query(Object f){
		StringBuilder sb=new StringBuilder();
		//获取到f的Class
		Class c=f.getClass();
		//获取table的名字
		boolean exists=c.isAnnotationPresent(Table.class);
		if(!exists){
			return null;
		}
		Table t=(Table) c.getAnnotation(Table.class);
		String tablename=t.value();
		sb.append("select * from ").append(tablename).append(" where 1=1");
		
		//遍历所有的字段
		Field[] fArray=c.getDeclaredFields();
		for(Field field:fArray){
			
			boolean fExists=field.isAnnotationPresent(Column.class);
			if(!fExists){
				continue;
			}
			Column column=field.getAnnotation(Column.class);
			String columnName=column.value();
			//拿到字段的名字
			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(f);
			} catch (Exception e) {
				e.printStackTrace();
			}
			//拼装sql
			if(fieldValue==null||(fieldValue instanceof Integer &&(Integer)fieldValue==0)){
				continue;
			}
			sb.append(" and ").append(columnName);
			if(fieldValue instanceof String){
				if(((String)fieldValue).contains(",")){
					String[] values=((String)fieldValue).split(",");
					sb.append(" in(");
					for(String v:values){
						sb.append("'").append(v).append("'").append(",");
					}
					sb.deleteCharAt(sb.length()-1);
					sb.append(")");
				}else{
					sb.append("=").append("'").append(fieldValue).append("'");
				}				
			}else if(fieldValue instanceof Integer){
				sb.append("=").append(fieldValue);
			}
		}
		return sb.append(";").toString();	
	}
	
	
	public static void main(String[] args){
	    Filter f1=new 	Filter();
		f1.setId(10);     //查询id为10的用户
		f1.setCity("浙江衢州");
	
		Filter f2=new 	Filter();
		f2.setEmail("liu@sina.com,zh@163.com,77777@qq.com");	
		
		
		String sql1=query(f1);
		String sql2=query(f2);
		System.out.println(sql1);
		System.out.println(sql2);
		
	}
}



运行结果:

select * from user where 1=1 and id=10 and city='浙江衢州';
select * from user where 1=1 and email in('liu@sina.com','zh@163.com','77777@qq.com');



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值