Java注解

注解的概念

注解是一种能被添加到java代码中的元数据,类、方法、变量、参数和包都可以用注解来修饰。注解对于它所修饰的代码并没有直接的影响。
通俗点说,就是给修饰的代码添加标签

基本语法

声明注解:
public @interface CherryAnnotation {

}
注解类型的实现部分:
public @interface CherryAnnotation {
public String name();
int age() default 18;
int[] array();
}
定义注解类型元素时需要注意如下几点:

  1. 访问修饰符必须为public,不写默认为public;
  2. 该元素的类型只能是基本数据类型、String、Class、枚举类型、注解类型(体现了注解的嵌套效果)以及上述类型的一位数组;
  3. 该元素的名称一般定义为名词,如果注解中只有一个元素,请把名字起为value(后面使用会带来便利操作);
  4. ()不是定义方法参数的地方,也不能在括号中定义任何参数,仅仅只是一个特殊的语法;
  5. default代表默认值,值必须和第2点定义的类型一致;
  6. 如果没有默认值,代表后续使用注解时必须给该类型元素赋值。

常用的元注解

@Documented
表示是否将注解信息添加在 Java 文档,即 Javadoc 中
@Inherited
Inherited 是指继承,@Inherited 定义了一个注释与子类的关系。如果一个超类带有 @Inherited 注解,那么对于该超类,它的子类如果没有被任何注解应用的话,那么这个子类就继承了超类的注解。
@Repeatable
通常使用 @Repeatable 的时候指注解的值可以同时取多个。

  @interface Persons {
    Person[] value();
}

@Repeatable(Persons.class)
@interface Person {
    String role default "";
}

@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan {
    ...
}

按照规定,如果使前面的 Persons 里面可以重复调用某个注解,则 Persons 必须有一个 value 的属性,且属性类型必须为被 @Repeatable 注解的 Person。

@Target
专门用来限定某个自定义注解能够被应用在哪些Java元素上面
以下是target的类型

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}


//@CherryAnnotation被限定只能使用在类、接口或方法上面
@Target(value = {ElementType.TYPE,ElementType.METHOD})
public @interface CherryAnnotation {
    String name();
    int age() default 18;
    int[] array();
}

@Retention
注解的生命周期有三个阶段:
1、Java源文件阶段;
2、编译到class文件阶段;
3、运行期阶段


public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     * 注解只在源码阶段保留,在编译器完整编译之后,它将被丢弃忽视
     * 例如 @Override, @SuppressWarnings
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     *  注解只被保留到编译进行的时候,它并不会被加载到 JVM 中;
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     * 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时,通过反射可以获取到它们;接触到的大部分注解都是runtime声明周期
     */
    RUNTIME
}

注解的属性

注解只有成员变量,没有方法。

此外,注解可以有默认值,需要用 default 关键字指定
例如 String name() default “AAA”;



@Retention(RetentionPolicy.RUNTIME)
//在运行期的加载阶段被加载到Class对象中
//在程序运行阶段,我们可以通过反射得到这个注解,并通过判断是否有这个注解或这个注解中属性的值,从而执行不同的程序代码段
@Target(value = {ElementType.METHOD})//用来描述方法
@Documented//是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中
public @interface CherryAnotation {
    String name();
    int age() default 18;
    int []score();
}

赋值采用key - value的形式


public class Student {
   @CherryAnotation(name="cherry-peng",age = 23,score = {100,12,45})
    public void study(int times){
        for(int i=0;i<times;i++){
            System.out.println("Study!");
        }
    }
}

此外,如果注解内只有一个名为 value 的属性时,应用该属性时可以将值直接写到括号内

public @interface language {
    String value();
}


// 第一种声明
@language("JAVA")
int coderA;
// 第二种声明
@language(value = "JAVA")
int coderA;

注解与反射机制

package myAnotation;

import java.lang.annotation.*;
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DocumentA {
}
package myAnotation;

import java.lang.annotation.*;

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DocumentB {
}
@DocumentA
 class A {

}
@DocumentB
public class DocumentDemo extends A{

    public static void main(String... args){

        Class<?> clazz = DocumentDemo.class;
        //根据指定注解类型获取该注解
        DocumentA documentA=clazz.getAnnotation(DocumentA.class);
        System.out.println("A:"+documentA);

        //获取该元素上的所有注解,包含从父类继承
        Annotation[] an= clazz.getAnnotations();
        System.out.println("an:"+ Arrays.toString(an));
        //获取该元素上的所有注解,但不包含继承!
        Annotation[] an2=clazz.getDeclaredAnnotations();
        System.out.println("an2:"+ Arrays.toString(an2));

        //判断注解DocumentA是否在该元素上
        boolean b=clazz.isAnnotationPresent(DocumentA.class);
        System.out.println("b:"+b);

    }
}

输出结果:

A:@myAnotation.DocumentA()
an:[@myAnotation.DocumentA(), @myAnotation.DocumentB()]
an2:[@myAnotation.DocumentB()]
b:true

删去DocumentA中的@Inherited
输出结果:

A:null
an:[@myAnotation.DocumentB()]
an2:[@myAnotation.DocumentB()]
b:false
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值