在SpringBoot中,注解太多了,但是不知道注解是怎么工作的,所以我就开始研究注解的开发和使用,本文章就从java注解开始学习。
在java中,内置了3种注解(元数据)分别是@Override,@Deprecated和@SuppressWarnings。当然只有这3中是远远不够的所以还定义了4种注解,专门用来创建其他注解的,就是自定义注解,我们接下来要学习的是如何自定义自己的注解和使用注解。
一.准备知识:
注解 说明
@Target 用来定义你的注解是用在什么地方,可以多选,如类,方法还是字段。ElementType参数包括:CONSTRUCTOR:构造器的声明,FIELD:域声明,LOCAL_VARIABLE:局部变量声明,METHOD:方法声明,PACKAGE:包声明,PARAMETER:参数声明,TYPE:类,接口,emum声明
@Retention 用来定义在什么时候保存这注解,参数有:SOURCE:注解被编译器去掉,CLASS:注解在class文件可以用,但是被VM去掉,REUNTIME:在VM种也能用,可以用反射机制获取信息
@Documented 将注解包含在Javadoc种
@Inherited 允许子类继承父类中的注解
2.Class类中getMethods() 与getDeclaredMethods() 方法的区别
public Method[] getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。
public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。
3.getDeclaredField和getField区别
getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。
getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
4.getAnnotation()方法
java.lang.Package.getAnnotation(Class annotationClass) 方法返回该元素的指定类型的注释,如果是这样的注释,否则返回null。
5.isAnnotationPresent()
java.lang.Package.isAnnotationPresent(Class annotationClass) 方法返回true,如果指定类型的注释存在于此元素上,否则返回false。
二.例子
先自定义注解:
/**
* 水果名称注解
* @author peida
*
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
String value() default "";
}
/**
* 水果颜色注解
* @author peida
*
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
/**
* 颜色枚举
* @author peida
*
*/
public enum Color{ BULE,RED,GREEN};
/**
* 颜色属性
* @return
*/
Color fruitColor() default Color.GREEN;
}
/**
* 水果供应者注解
* @author peida
*
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {
/**
* 供应商编号
* @return
*/
public int id() default -1;
/**
* 供应商名称
* @return
*/
public String name() default "";
/**
* 供应商地址
* @return
*/
public String address() default "";
}
如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了。使用注解的过程中,很重要的一部分就是创建于使用注解处理器。Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处理器
自定义注解处理器
public class FruitInfoUtil {
public static void getFruitInfo(Class clazz){
String strFruitName=" 水果名称:";
String strFruitColor=" 水果颜色:";
String strFruitProvicer="供应商信息:";
Field[] fields = clazz.getDeclaredFields();
for(Field field :fields){
if(field.isAnnotationPresent(FruitName.class)){
FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);
strFruitName=strFruitName+fruitName.value();
System.out.println(strFruitName);
}
else if(field.isAnnotationPresent(FruitColor.class)){
FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class);
strFruitColor=strFruitColor+fruitColor.fruitColor().toString();
System.out.println(strFruitColor);
}
else if(field.isAnnotationPresent(FruitProvider.class)){
FruitProvider fruitProvider= (FruitProvider) field.getAnnotation(FruitProvider.class);
strFruitProvicer=" 供应商编号:"+fruitProvider.id()+" 供应商名称:"+fruitProvider.name()+" 供应商地址:"+fruitProvider.address();
System.out.println(strFruitProvicer);
}
}
}
}
测试
public class FruitRun {
/**
* @param args
*/
public static void main(String[] args) {
FruitInfoUtil.getFruitInfo(Apple.class);
}
}
====================================
水果名称:Apple
水果颜色:RED
供应商编号:1 供应商名称:陕西红富士集团 供应商地址:陕西省西安市延安路89号红富士大厦
三.注意:
默认值限制:
编译器对元素的默认值有些过分挑剔。首先,元素不能有不确定的值。也就是说.,元素必须要么具有默认值,要么在使用注解时提供元素的值。 其次,对于非基本类型的元素,无论是在源代码中声明时,或是在注解接口中定义默认值时,都不能以null作为其值。这个约束使得处理器很难表现一个元素的存在或缺失的状态,因为在每个注解的声明中,所有的元素都存在,并且都具有相应的值。为了绕开这个约束,我们只能自己定义一些特殊的值,例如空字符串或负数,以此表示某个元素不存在.
原创来源:滴一盘技术