注解(Annotation),实际上和属性、方法同样,都是一个类的组成部分,不过对于初学者来讲仍是有点陌生的,由于注解是给别人用的,而属性和方法都是本身用的,这就致使没有对注解进行深刻的学习,而在使用别人框架的时候,才被迫去了解框架提供的注解的使用方法。java
注解的形式都是以@开头,在微博微信中@Somebody是通知某人,而注解的@Info,则表示通知一件事(代表一种状态),具体通知谁不去管,具体谁去用也无论,谁对这个注解感兴趣谁来用。api
咱们从最简单的例子提及,最经常使用的就是@Override,@Deprecated,@SuppressWarnings。若是按照上面的说法来讲明,这三个注解都是给编译器使用的。数组
@Override:代表这个方法是重写的父类的方法,当你把@Override放到一个方法上时,编译器会自动去父类中查找是否有相应的方法,若是没有,说明注解使用错误,或者重写的方法名、参数等写错了,那么编译器就会给出编译错误,让你去修改。微信
@Deprecated:代表这个属性被弃用,当你使用它的时候,编译器就会给出提醒。框架
@SuppressWarnings:代表这不是一个警告,那么编译器就不会把它当作警告给提示出来。ide
也就是说,注解的使用方便了别人去作某些事情,若是不用注解的话用配置文件也能够,可是针对上面三个注解,若是写在配置文件中,那么编译器要怎么知道去哪一个配置文件中去读,又要以怎样的格式去读,这都是一个问题,而使用注解听从了一种约定大于配置的理念。学习
因此使用注解的时候就要明白这个注解是给谁用的,用做什么。spa
而当你打算写一个框架时,也能够提供注解的方式给别人使用,这样来讲更方便,而对于你来讲就要以解析注解的方式来代替读取并解析配置文件的方式。设计
注解也是有相应的属性的,也就是说当定义一个注解的时候指定注解的属性。code
首先了解一下能够被注解的位置有哪些,这些都在一个枚举类:ElementType当中:
注解位置配合@Target使用,当只有一个位置时能够这么使用:
@Target(ElementType.ANNOTATION_TYPE)
当指定多个位置时,使用方法以下:
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
若是一个注解没有指定注解位置,那么它能够应用于全部位置。
注解也是有相应的声明周期的,也是封装在一个枚举类:RetentionPolicy中:
声明周期配合@Retention来使用,使用方法以下:
@Retention(RetentionPolicy.RUNTIME)
通常来讲对于编写框架用的注解的生命周期都是RUNTIME。
注解和接口其实很类似,接口里面的方法定义了行为,注解的方法定义了属性,下面先给一个例子:
public @interface MyAnnotation { //声明属性,可使用以下类型 String name(); String password() default "123"; int age() default 12; TimeUnit gender() default TimeUnit.SECONDS; Class<?> clazz(); int[] arr() default {1,2,3}; //为了嵌套配置 Override my2(); }
简单总结下:
当你提供一个注解供别人使用时,那么对方可能将注解应用于容许的位置,并有可能赋值,而咱们没法知道注解具体的位置,这时候只能经过反射加遍历的方式来得到注解的位置。下面给出一个例子:
package yiwangzhibujian.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; public class UseAnnatation { public static void main(String[] args) throws Exception { Dog dog=new Dog(); Field[] fields = Dog.class.getFields(); for(Field field:fields){ DefaultValue annotation = field.getAnnotation(DefaultValue.class); if(annotation!=null){ String value = annotation.value(); field.set(dog, value); } } System.out.println(dog); } } class Dog{ @DefaultValue("little white") public String name; public int age; public String toString() { return "Dog [name=" + name + ", age=" + age + "]"; } } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface DefaultValue{ String value(); }
这个例子作了以下事:
固然这个例子只是举例说明注解的用法,默认值根本就不用这么复杂的方式,若是用过Spring的话,应该知道自动注入的注解,实现原理就是经过这种方式。
除了一开始说的@Override,@Deprecated,@SuppressWarnings三个注解之外,jdk还有其余注解,简单来讲,如今介绍的时候就会贴出源码。
@Documented:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }
这个注解用来代表,在生成api文档的时候将注解的对象生成文档。
@Inherited:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }
被注解的注解,将会有被子类继承。
@Repeatable:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Repeatable { Class<? extends Annotation> value(); }
被注解的注解,能够在一个属性上重复使用。
@Native:
@Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.SOURCE) public @interface Native { }
代表一个字段引用的值可能来自于本地代码,暂未找到具体示例,后续补上。
说到底,注解的使用方仍是很简单的,难点在于提供给你注解的人是怎么经过注解去达到他的目的的。若是你设计一个框架并提供注解给人使用,那么你就要精通反射。不过通常状况下是不多遇到须要自定义反射的场景,除非你设计一个中间框架,别人经过你的框架来调用本身实现的类,就像Spring同样。