注解
基础
1.java中内置的三种注解
@Override: 重写方法,或者实现接口
@Deprecated:不鼓励使用,很危险或者是有更好的替代。
@SuppressWarnings: 压制警告
2.元注解
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它annotation类型作说明。
1.@Target
表示该注解可以用于什么地方,可能的ElementType参数包括:
- CONSTRUCTOR:构造器的声明
 - FIELD:域声明(包括enum实例)
 - LOCAL_VARIABLE:局部变量声明
 - METHOD:方法声明
 - PACKAGE:包声明
 - PARAMETER:参数声明
 - TYPE:类,接口(包括注解类型)或enum声明
 
2.@Retention
表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:
- SOURCE:注解将被编译器丢弃
 - CLASS:注解在class文件中可用,但会被VM丢弃
 - RUNTIME:VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息。
 
3.@Documented
将此注解包含在JavaDoc中
4.@Inherited
允许子类继承父类中的注解
Class,Method,Field等类都实现了AnnotatedElement接口
3.注解元素可用的类型
八大基本类型,String,Class,enum,Annotaion,以上的数组,注解允许嵌套
Effective java
- 
    
注解优先于命名模式
a.既然有了注解,就完全没有理由再使用命名模式了
 - 坚持使用
@Override注解 - 
    
用标记接口定义类型: 标记接口和注解一样,只是告诉jvm此类具备标记接口所标示的能力,如Serializable,Cloneable
a.标记接口是没有包含方法的接口,而只是标明一个类实现了具有某种属性的接口,eg Serializable,通过实现这个接口,类表明它的实例可以被写到ObjectOutputStream
b.标记接口定义的类型是由被标记类的实例实现的,标记注解则没有定义这样的类型,这个类型允许你在编译时捕捉,在使用标记注解的情况下要到运行时才能捕捉到的错误
c.标记接口胜过标记注解的另一个优点是,它们可以被更加精确地进行锁定
d.标记注解可以通过默认的方式添加一个或者多个注解类型元素,给已被使用的注解类型添加更多地信息 - 
    
什么时候该使用标记注解,什么时候应该使用标记接口?
a.如果标记是应用到任何程序元素而不是类或者接口,就必须使用注解
b.如果标记只是应用到类和接口,并且需要编写一个或多个只针对这种标记的方法,就要考虑使用标记接口,可以提供编译时的类型检查.
c.如果标记只是应用到类和接口,并且我要永远限制这个标记只用于特殊接口的元素.最好将标记定义成该接口的一个子接口(eg Set) 
自定义注解
    //Age
    @Target({ ElementType.METHOD, ElementType.FIELD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Age {
        public int value() default 0;
    }
    //Hometown
    @Target({ ElementType.METHOD, ElementType.FIELD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Hometown {
        public String value() default "";
    }
    //Name
    @Target({ ElementType.METHOD, ElementType.FIELD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Name {
        public String value() default "";
    }
    //User
    public class User {
        @Name(value = "lcj")
        private String name;
        @Hometown(value = "henan")
        private String hometown;
        @Age(value = 22)
        private Integer age;
        ...
        getter/setter
        @Override
        public String toString() {
            return MoreObjects.toStringHelper(User.class).add("name", this.getName()).add("hometown", this.getHometown())
                .add("age", this.getAge()).toString();
        }
    }
    @Test
    public void getUserAnnotation() {
        User user = new User();
        Field[] fields = User.class.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if ("name".equals(field.getName())) {
                Name name = field.getAnnotation(Name.class);
                user.setName(name.value());
                System.out.println(name.value());
            }
            if ("hometown".equals(field.getName())) {
                Hometown hometown = field.getAnnotation(Hometown.class);
                user.setHometown(hometown.value());
                System.out.println(hometown.value());
            }
            if ("age".equals(field.getName())) {
                Age age = field.getAnnotation(Age.class);
                user.setAge(age.value());
                System.out.println(age.value());
            } else {
                continue;
            }
        }
        System.out.println(user);
    }