Java注解-----Annotation浅析

最近项目要添加摇一摇和试吃功能(感觉low到爆),开发周期比较紧,博客也有几天没更新了,今天抽空再来一篇。
注解是JDK1.5之后才有的新特性,现在使用已经非常普遍了。最近刚好项目里用到了,现在做一下总结。

初识注解

我们先看JDK1.5之后提供的三个注解:

注解释义
@Deprecated废弃的,过时的,不建议使用的
@Override重写、覆盖
@SuppressWarnings压制警告信息,防止报黄线警告
public class Test {

    @SuppressWarnings(":deprecation") //压制警告信息
    private void method1() {

    }

    @Deprecated     //JDK自带注解,过时的,不建议使用
    private void method2() {
    }

    @Override       //JDK自带注解,重写(覆盖)Object父类的toString()
    public String toString() {
        return super.toString();
    }
}

注解的使用

上面我们介绍了三种JDK自带的注解,其实注解的使用和普通修饰符(public,static,void等)区别并不大。使用注解相当于为程序加上某种标记,这个标记可以加在包,类,属性,方法,方法参数以及局部变量上。
下面列举注解在代码中的使用

@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = ElementType.TYPE)
public @interface ModelPanel {
}

@interface:是一个关键字,在设计注解的时候必须把这个类型定义为@interface,而不能用class或interface关键字
@Target:用来约束注解可以应用的地方(如方法、类或字段),其中ElementType是枚举类型,其定义如下,也代表可能的取值范围。
注意:当注解未指定Target值时,则此注解可以用于任何元素之上,多个值使用{}包含并用逗号隔开,例:

   //这是我们项目中用到的注解类
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.FIELD,ElementType.METHOD,ElementType.CONSTRUCTOR})
public @interface ModelPanel {
}
public enum ElementType {
    /** 标明该注解可以用于类、接口(包括注解类型)或enum声明 */
    TYPE,

    /** 标明该注解可以用于字段(域)声明,包括enum实例 */
    FIELD,

    /** 标明该注解可以用于方法声明 */
    METHOD,

    /** 标明该注解可以用于参数声明 */
    PARAMETER,

    /** 标明注解可以用于构造函数声明 */
    CONSTRUCTOR,

    /** 标明注解可以用于局部变量声明 */
    LOCAL_VARIABLE,

    /** 标明注解可以用于注解声明(应用于另一个注解上)*/
    ANNOTATION_TYPE,

    /** 标明注解可以用于包声明 */
    PACKAGE,

    /**
     * 标明注解可以用于类型参数声明(1.8新加入)
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * 类型使用声明(1.8新加入)
     * @since 1.8
     */
    TYPE_USE
}

@Retention用来设置注解的生命周期,分别有三个值,源码级别(source),类文件级别(class)或者运行时级别(runtime),其含义如下:

  • @Retention(value = RetentionPolicy.SOURCE)
    这个注解的意思是让注解只在java源文件中存在,编译成.class文件后注解被丢弃了
  • @Retention(value = RetentionPolicy.CLASS)
    这个注解的意思是让注解在java源文件(.java文件)中存在,编译成.class文件后注解也还存在,被ModelPanel注解类标识的类被类加载器加载到内存中后ModelPanel注解就不存在了,当注解未定义Retention值时,默认值是CLASS
  • @Retention(value = RetentionPolicy.RUNTIME)
    这个注解的意思是让注解在程序运行期(JVM)一直保留,因此可以通过反射机制读取注解的信息。

当在Java源程序上加了一个注解,这个Java源程序要由javac去编译,javac把java源文件编译成.class文件,在编译成class时可能会把Java源程序上的一些注解给去掉,java编译器(javac)在处理java源程序时,可能会认为这个注解没有用了,于是就把这个注解去掉了,那么此时在编译好的class中就找不到注解了, 这是编译器编译java源程序时对注解进行处理的第一种可能情况,假设java编译器在把java源程序编译成class时,没有把java源程序中的注解去掉,那么此时在编译好的class中就可以找到注解,当程序使用编译好的class文件时,需要用类加载器把class文件加载到内存中,class文件中的东西不是字节码,class文件里面的东西由类加载器加载到内存中去,类加载器在加载class文件时,会对class文件里面的东西进行处理,如安全检查,处理完以后得到的最终在内存中的二进制的东西才是字节码,类加载器在把class文件加载到内存中时也有转换,转换时是否把class文件中的注解保留下来,这也有说法,所以==说一个注解的生命周期有三个阶段:java源文件是一个阶段,class文件是一个阶段,内存中的字节码是一个阶段,javac把java源文件编译成.class文件时,有可能去掉里面的注解,类加载器把.class文件加载到内存时也有可能去掉里面的注解,因此在自定义注解时就可以使用Retention注解指明自定义注解的生命周期,自定义注解的生命周期是在RetentionPolicy.SOURCE阶段(java源文件阶段),还是在RetentionPolicy.CLASS阶段(class文件阶段),或者是在RetentionPolicy.RUNTIME阶段(内存中的字节码运行时阶段),根据JDK提供的API可以知道默认是在RetentionPolicy.CLASS阶段== (JDK的API写到:the retention policy defaults to RetentionPolicy.CLASS.)
(摘自https://www.cnblogs.com/xdp-gacl/p/3622275.html)

注解元素及其数据类型

上述@ModelPanel内部没有定义其他元素,所以@ModelPanel也称为标记注解(marker annotation),但在自定义注解中,一般都会包含一些元素以表示某些值,方便处理器使用,这点在下面的例子将会看到:

@Retention(value = RetentionPolicy.RUNTIME)  //在程序运行中一直存在
@Target(value = ElementType.TYPE)            //只能作用到类上
public @interface ModelPanel {
    boolean needLogin() default false;  //该界面是否需要登录才能访问,默认不需要
}

如上定义名为ModelPanel的注解,与前面注解不同的是,我们声明一个boolean类型的needLogin元素,其默认值为false,但是必须注意到对应任何元素的声明应采用方法的声明方式,同时可选择使用default提供默认值,@ModelPanel使用方式如下:

//在类上使用该注解

@ModelPanel(needLogin = false)
public class MainActivity{

}

关于注解支持的元素数据类型除了上述的String,还支持如下数据类型


  • 所有基本类型(int,float,boolean,byte,double,char,long,short)
  • String
  • Class
  • enum
  • Annotation
  • 上述类型的数组

倘若使用了其他数据类型,编译器将会丢出一个编译错误,注意,声明注解元素时可以使用基本类型但不允许使用任何包装类型,同时还应该注意到注解也可以作为元素的类型,也就是嵌套注解。
  public static void main(String[] args) {
    /*
     * 用反射方式获得注解对应的实例对象后,在通过该对象调用属性对应的方法
     */
     ModelPanel modelPanel = currentClass.getAnnotation(ModelPanel.class);
     System.out.println(modelPanel.needLogin()); 
     }
Value 属性

如果注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默认值或者你只有一个value属性),那么可以省略掉“value=”部分。
定义如下:

@Retention(value = RetentionPolicy.RUNTIME)  //在程序运行中一直存在
@Target(value = ElementType.TYPE)            //只能作用到类上
public @interface ModelPanel {
    String value();                     //定义一个名称为value的属性
    boolean needLogin() default false;  //该界面是否需要登录才能访问,默认不需要
}

使用如下:

//在类上使用该注解

@ModelPanel("test")  //  等于@ModelPanel(value="test")  
public class MainActivity{

}

以上为个人理解的注解用法,更深入的用法暂时没用到,等以后有时间再补上,趁着中午发了博客,下午还得继续赶项目。(略略略。。。)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值