这篇文章将会带领你了解Java注解,注解的使用,注解的解析,利用反射解析运行时注解,相信有一定Java基础的小伙伴一定会接触大量的注解,Spring , Hibernate , MyBatis等著名的框架也有很多关于注解方面的应用,对于注解的使用小伙伴们应该一点都不陌生,那么如何自定义注解呢?学会自定义注解有什么好处呢?
下面就随笔者进入注解的世界
很多小伙伴在学习注解之前,都不知道学习注解到底可以用来干什么,可以给自身带来什么好处,那么在这里,笔者描述学习注解的几点好处
注解是Java1.5,JDK5.0引用的技术,与类,接口,枚举处于同一层次 。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释 。
在Java中,自带了三种注解,这三种注解存在于java.lang包中,首先我们讲一讲这些注解
首先,自定义注解我们必须了解四个元注解,什么是元注解?元注解指作用于注解之上的元数据或者元信息,简单通俗的讲,元注解就是注解的注解 .
Documented与Inherited是典型的标识性注解,也就是说在注解内部并没有成员变量,没有成员变量的注解称为标识注解
Target主要的参数类型包括以下几种
Retention主要的参数类型包括以下几种
首先,我们来看一段自定义注解实现的代码
@Documented
@Inherited
//该注解可以作用于方法,类与接口
@Target({ElementType.METHOD,ElementType.TYPE})
//JVM会读取注解,所以利用反射可以获得注解
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
//定义成员变量
//成员变量可以通过default指定默认值
//如果成员变量不指定默认值的情况下
//我们在引用接口时则必须给没有默认值的成员变量赋值
String name() ;
int age() default 18 ;
}
@interface 用于定义注解接口,接口中只能定义成员变量,且定义的成员变量必须以()结尾,可以使用default关键字为成员变量指定默认值,如果不为成员变量指定默认值的情况,则必须在引用注解时,对没有默认值的成员变量进行赋值操作
注解的使用规则:
//@注解名(变量1=变量1值,变量2=变量2值,...)
//如果注解中拥有数组类型,假设是String类型,那么赋值方式可以如下
//@注解名(String数组名称={"tset1","test2","test3"})
@TestAnnotation(name="Taro")
//因为我们注解中的age()是拥有默认值的,所以这边可以不为age()赋值
//如果我们的注解中只有一个成员变量,且成员变量的名称为value()
//那么可以使用如下赋值方式
//@注解名(属性值)
//如果我们的注解中没有成员变量,那么此时的注解被称为标识注解
注解中可以定义的数据类型是受到限制的,除了基本类型之外,String,Enums,Annotation,Class还有这些类型的数组
如何使用我们刚刚定义的注解呢?刚刚的注解我们声明了是针对方法和类或者接口生效,那么我们来看看使用方法
@TestAnnotation(name="I'm class annotation")
public class Test {
@TestAnnotation(name="I'm method annotation")
public static void showAnnotation(){
}
}
怎么样,是不是很easy呢?
主要使用Java的反射原理实现对注解的解析,不太懂反射的小伙伴通过笔者的注释看起来也不会很难
PS :下一篇博文是对Java反射的详解
public static void main(String[] args) {
//解析注解
//获得我们需要解析注解的类
Class clz = Test.class;
//解析Class
//由于我们的注解是可以给类使用的,所以首先判断类上面有没有我们的注解
//判断类上面是否有注解
boolean clzHasAnnotation = clz.isAnnotationPresent(TestAnnotation.class);
if(clzHasAnnotation){
//类存在我们定义的注解
//获得注解
TestAnnotation clzAnnotation = clz.getAnnotation(TestAnnotation.class);
//输出注解在类上的属性
System.out.println("name="+clzAnnotation.name()+"\tage="+clzAnnotation.age());
}
//解析Method
//两种解析方法上的注解方式
//获得类中所有方法
Method[] methods = clz.getMethods();
//第一种解析方法
for(Method m : methods){
//获得方法中是否含有我们的注解
boolean methodHasAnnotation = m.isAnnotationPresent(TestAnnotation.class);
if(methodHasAnnotation){
//注解存在
//获得注解
TestAnnotation methodAnnotation = m.getAnnotation(TestAnnotation.class);
System.out.println("name="+methodAnnotation.name()+"\tage="+methodAnnotation.age());
}
}
//第二种解析方式
for(Method m : methods){
//获得方法上所有注解
Annotation[] annotations = m.getAnnotations();
//循环注解
for(Annotation a : annotations){
//如果是我们自定义的注解
if(a instanceof TestAnnotation){
//输出属性,需要强制装换类型
System.out.println("name="+((TestAnnotation)a).name()+"\tage="+((TestAnnotation)a).age());
}
}
}
}
最后得出结果,因为我们使用了两种解析Method注解的方式,所以最终会得到两个Method上面的字符串
好了,这篇博文就到这里,希望会帮到小伙伴们