Java 之注解(Annotation)

本文详细介绍了Java注解的用途、基本注解、JDK的元注解、自定义注解、Java8的新特性,包括重复注解和类型注解,以及编译时处理注解的原理和实现。通过注解,可以为程序元素添加元数据,实现编译期和运行时的自动化处理。Java8的新特性使得注解的使用更加灵活,如支持重复注解,增强了类型注解的功能。
摘要由CSDN通过智能技术生成

 

1.Annotation为何而来

What:Annotation干嘛的

  • JDK5开始,java增加了对元数据(MetaData)的支持,怎么支持?答:通过Annotation(注解)来实现。Annotation提供了为程序元素设置元数据的方法。元数据:描述数据的数据。

  • Annotation可以为哪些程序元素设置元数据呢? Annotation提供了一种为程序元素设置元数据的方法,包括修饰包、类、构造器、方法、成员变量、参数、局部变量的声明。元数据的信息被存储在Annotation的“name=value”对中。

  • Annotation怎么实现设置元数据?程序如何读取这些元数据?答:元数据的信息被存储在Annotation的“name=value”对中。Annotation是一个接口,程序可以通过反射来获取指定程序元素的Annotation对象,然后通过Annotation对象来取得注解里的元数据。

  • Annotation不影响程序代码的执行,无论增加、删除Annotation,代码都始终如一的执行。如果希望让程序中的Annotation在运行时起一定的作用,只有通过某种配套工具对Annotation中的信息进行访问和处理。jdk7之前访问和处理Annotation的工具统称APT(Annotation Processing Tool)(jdk7后就被废除了),jdk7及之后采用了JSR 269 API。相关原因官方说明原因

  • 结论:java想给程序元素提供元数据支持,于是创造了Annotation来实现这个目标。

注解的使用案例

@Entity
public class Book {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
}

Why:为什么要提供元数据支持

  • 通过Annotation设置的元数据在什么时候被读取?读取能干嘛?答:Annotation就像代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取。读取到了程序元素的元数据,就可以执行相应的处理。通过注解,程序开发人员可以在不改变原有逻辑的情况下,在源代码文件中嵌入一些补充信息。代码分析工具、开发工具和部署工具可以通过解析这些注解获取到这些补充信息,从而进行验证或者进行部署等。

  • 比如:上面代码,读取到 id变量上面有@GeneratedValue(strategy=GenerationType.AUTO)注解,并且注解提供了strategy=GenerationType.AUTO这样的元数据信息,那么程序就会为id设置一个自增的值。读取到Book类上面有一个@Entity注解,程序就会认为这是一个持久化类,就会做一些持久化的处理。

  • 不使用Annotation怎么为程序元素提供元数据
    看来元数据在编程中还是能起到很大的作用的,如果没有元数据还真的不好办,比如上面代码中id成员变量的元数据是“strategy=GenerationType.AUTO即采用自增策略”,如果没有这个元数据支持,程序中怎么才能为id赋一个自增的值呢?忧愁。

  • 提供元数据只有通过Annotation才可以吗?答:不是,通过配置文件也可以。比如还是上面代码id这个变量,我现在想为它添加描述数据即元数据,内容是:采用自增策略。这个信息通过Annotation来实现就是上面代码的样子。通过配置文件实现的话,比如采用xml格式配置文件。那么我可以在文件中配置<property-MetaData class="Book " property="id" metadata="auto">。哈哈!比如我就定一个规则:class表示类,property表示类的某个属性,metadata是属性的元数据。程序在启动时通过读取这个文件的信息就可以知道id变量的元数据了,知道元数据就可以做相应处理了。当然,通过配置文件还是没有注解方便。


知道元数据在编程中的重要性和提供元数据的方法Annotation了,那么就来学习Annotation吧。

  • 提示:有些注解只是为了防止我们犯低级错误,通过这些注解,让编译器在编译期就可以检查出一些低级错误,对于这些注解,可以加或者不加,当然还有很多其他注解都是起辅助编程作用。但是有一些注解的作用很重要,不加的话就实现不了一些功能,比如,数据持久化操作中,通过@Entity注解来标识持久化实体类,如果不使用该注解程序就识别不了持久化实体类。

2.基本Annotation

  • Java提供了5个基本的Annotation的用法,在使用Annotation时要在其前面增加@符号。

  • @Override :限定重写父类方法

  • @Deprecated:表示已过时

  • @SuppressWarnings:抑制编译警告

  • @SafeVarargs (java7新增):去除“堆污染”警告

  • @Functionlnterface (java8新增):修饰函数式接口

  • @Override :用来指定方法覆载的,它可以强制一个子类必须覆盖父类的方法。写在子类的方法上,在编译期,编译器检查这个方法,保证父类包含被该方法重写的方法,否则编译出错。该注解只能修饰方法,在编译期被读取。

  • @Deprecated:用于表示某个程序元素(类、方法等)已过时。编译时读取,编译器编译到过时元素会给出警告。

  • @SuppressWarnings:抑制编译警告,被该注解修饰的程序元素(以及该程序元素中的所有子元素)取消显示指定的编译警告。
    比如:取消如果程序使用没有泛型限制的集合会引起编译器警告,为了避免这种警告使用该注解。

    • unchecked异常:运行时异常。是RuntimeException的子类,不需要在代码中显式地捕获unchecked异常做处理。Java异常
@SuppressWarnings(value="unchecked")
public class SuppressWarningTest{
   public static void main(String[] args)
   {
       List<String> myList = new ArrayList();
   }
}
@SuppressWarnings("deprecation")   //取消过时警告
    public HibernateTemplate getHt() {
        return ht;
    }
  • @SafeVarargs (java7新增):java7的“堆污染”警告与@SafeVarargs
    堆污染:把一个不带泛型的对象赋给一个带泛型的变量是,就会发生堆污染。
    例如:下面代码引起堆污染,会给出警告
List l2 = new ArrayList<Number>();
List<String> ls = l2;    
  • 3中方式去掉这个警告

    • 使用注解@SafeVarargs修饰引发该警告的方法或构造器。
    • 使用@SuppressWarnings("unchecked") 修饰。
    • 使用编译器参数命令:-Xlint:varargs
  • @Functionlnterface (java8新增):修饰函数式接口
    使用该注解修饰的接口必须是函数式接口,不然编译会出错。那么什么是函数式接口?答:如果接口中只有一个抽象方法(可以包含多个默认方法或static方法),就是函数式接口。
    如:

@Functionlnterface
public interface FunInterface{
  static void foo(){
   System.out.println("foo类方法");
  }
  default void bar(){
   System.out.println("bar默认方法");
  }
  void test();//只定义一个抽象方法,默认public
}

3.JDK的元Annotation

  • 元注解(Meta Annotation):和元数据一样,修饰注解的注解。
  • java提供了6个元注解(Meta Annotation),在java.lang.annotation中。其中5个用于修饰其他的Annonation定义。而@Repeatable专门用于定义Java8新增的重复注解。所以要定义注解必须使用到5个元注解来定义。

@Retention(英文:保留)

  • 用于指定被修饰的Annotation可以保留多长时间,只能修饰Annotation定义。@Retention包含一个RetentionPolicy类型的value成员变量,使用@Retention必须为该value成员变量指定值。value成员变量的值有3个选择:
  • RetentionPolicy.CLASS:编译器将把Annotation记录在class文件中。当运行java程序时,JVM不可获取Annotation信息。(默认值)
  • RetentionPolicy.RUNTIME:编译器将把Annotation记录在class文件中。当运行java程序时,JVM也可获取Annotation信息,程序可以通过反射获取该Annotation信息
  • RetentionPolicy.SOURCE:Annotation只保留在源代码中(.java文件中),编译器直接丢弃这种Annotation。
    案例:
//定义下面的Testable Annotation保留到运行时,也可以使用value=RetentionPolicy.RUNTIME
@Retention(RetentionPolicy.RUNTIME)
public @interface Testable{}

@Target ( 目标)

用于指定被修饰的Annotation能用于修饰哪些程序单元,只能修饰Annotation定义。它包含一个名为value的成员变量,取值如下:

  • @Target(ElementType.ANNOTATION_TYPE):指定该该策略的Annotation只能修饰Annotation.
  • @Target(ElementType.TYPE) //接口、类、枚举、注解
  • @Target(ElementType.FIELD) //成员变量(字段
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不甘于平凡的溃败

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值