什么是注解

  • 注解可以看作类的第6大要素(成员变量、构造器、方法、代码块、内部类)
  • 注解有点像修饰符,可以修饰一些程序要素:类、接口、变量、方法、局部变量等等
  • 注解要和对应的配套工具(APT:Annotation Processing Tool)一起使用,APT会对含有注解进行一些处理
  • 比如API文档里面,有些方法下边的“@Deprecated”,就是一个注解,它表示这个方法已经过时,使用的时候会收到警告
  • 注解完全不影响程序的功能

元注解

  • 元注解有6个,位于java.lang.annotation包下
  • @Retention
    • 只能修饰注解
    • 用于指定被修饰的注解,可以保留到什么时间
    • @Retention只有一个元素:value,是RetentionPolicy类型,这是个枚举类,只有如下三个值
      • RetentionPolicy.SOURCE:注解只保留在源代码中,编译阶段即被丢弃
      • RetentionPolicy.CLASS:保留在class文件中,程序运行时,JVM不能获取到该注解
      • RetentionPolicy.RUNTIME:保留在class文件中,程序运行时,可以通过反射获得该注解
  • @Target
    • 只能修饰注解
    • 用于指定被修饰的注解,可以用于修饰哪些程序元素
    • @Target只有一个元素:value,是ElementType[]类型,ElementType也是个枚举类,只有如下十个值
      • ElementType.TYPE:表示被修饰的注解可以修饰类、接口、注解、枚举
      • ElementType.FIELD:只能修饰成员变量
      • ElementType.METHOD:只能修饰方法
      • ElementType.PARAMETER:可以修饰参数
      • ElementType.CONSTRUCTOR:只能修饰构造器
      • ElementType.LOCAL_VARIBLE:只能修饰局部变量
      • ElementType.ANNOTATION_TYPE:只能修饰注解
      • ElementType.PACKAGE:只能修饰包
      • ElementType.TYPE_USE:since 1.8,表示注解能写在使用类型变量的语句中
      • ElementType.TYPE_PARAMETER:since 1.8,表示注解能写在类型变量的声明语句中
  • @Documented
    • 修饰注解,该注解将被javadoc提取进入文档
    • 该元注解没有元素
  • @Inherited
    • 修饰注解,表示该注解具有继承性
    • 比如:一个父类使用了一个注解X修饰,而X注解在定义时用了@Inherited修饰,那么子类自动被X修饰
  • @Repeatable
    • 用于修饰一个注解,表示该注解可以用于重复注解
    • 包含一个变量value,是Annotation的Class类型
  • @Native

基本注解

  • 基本注解有5个,位于java.lang包下
  • @Override
    • 只能修饰方法;保留在源代码阶段
    • 告诉编译器,被该修饰符修饰的方法是在重写父类的方法,如果父类中没有相同签名的方法,那么会发生错误
  • @Deprecated
    • 修饰构造器、成员变量、局部变量、方法、包、参数、类、注释、枚举;保留到运行阶段;javadoc提取
    • 表示该元素已过时,其他地方使用这些元素时,编译器会给出警告
  • @SuppressWarnings
    • 修饰类、接口、注解、枚举、成员变量、方法、参数、构造方法、局部变量;保留在源代码阶段;
    • 只有一个变量value,类型为String[]
    • 被修饰的程序元素及子元素取消value指定的编译器警告
  • @SafeVarargs
    • 修饰构造器、方法;保留在运行阶段;javadoc提取
    • 专门修饰会引发“堆污染”警告的方法或者构造器
    • since 1.7
  • @FunctionalInterface
    • 只能修饰接口;保留到运行阶段;javadoc提取
    • 告诉编译器严格检查,该接口为函数式接口
    • since 1.8

自定义注解

  • 自定义注解跟定义接口类似,只是用“@interface”关键字替换“interface”
  • 可以用一些元注解修饰即可,对于保留时间,如果不写@Target,那么默认是修饰任何程序要素
  • 可以包含变量
  • 比如@Deprecated的源代码是这样的
package java.lang;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*; @Documented //元注解:表示该注解会被javadoc提取到文档中
@Retention(RetentionPolicy.RUNTIME) //元注解:保留到运行阶段
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) //元注解:可以修饰的程序元素
public @interface Deprecated {
}
  • 再比如@SuppressWarnings的源代码
package java.lang;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*; @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value(); //可以包含变量,String[]是该变量的类型
}
  • 包含变量的时候,使用时就不能只写注解名称,还得写变量的值,比如:
@SuppressWarnings(value="unchecked")
//如果只有一个变量,那么可以省略变量名:
@SuppressWarnings("unchecked")
  • 不写变量名和值,那么该注解在定义的时候,就得定义默认值,用default关键字,比如
@Target({TYPE, FIELD})                   //只有一个变量,省略变量名
@Retention(RetentionPolicy.CLASS) //只有一个变量,省略变量名
public @interface Test{
String name() default "Java"; //用default指定默认值
int age() default 18; //用default指定默认值
}
  • 实际上,自定义注解默认都是继承了java.lang.annotation.Annotation接口的,见示例:
package testpack;
public class Test1 {
public static void main(String[] args){
Class clazz=Test.class;
Class[] is=clazz.getInterfaces();
for (Class i:is) {
System.out.println(i); //输出:interface java.lang.annotation.Annotation
}
}
}
@interface Test{ }

注解的分类

  • 标记注解:不包含成员变量
  • 元数据注解:包含成员变量

获取程序元素的注解信息

  • 光有注解没用,还得有对应的工具来处理,要处理,得先获取注解信息
  • 获取到注解信息的前提是,注解能保留到"获取"这个操作的时候
  • 在文章0033 Java学习笔记-反射-初步1中提到,通过反射可以获取一个类的注解信息,有六个方法,其实这些方法都来自于一个接口:java.lang.reflect.AnnotatedElement,Class是它的实现类之一
  • java.lang.reflect.AnnotatedElement是个接口,表示程序中可以接受注解的程序元素,主要有如下几个实现类
    • Package
    • Class
    • Filed
    • Constructor
    • Method
    • Parameter
  • 以上这些类都包含0033 Java学习笔记-反射-初步1中关于获取注解的那6个方法,
  • 除以上6个方法外,还有一个方法用于判断程序元素上是否存在指定类型的注解:boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
  • 见示例:
package testpack;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; @Test(name="Java",age=18)
public class Test1 {
public static void main(String[] args){
Class clazz=Test1.class;
Annotation a=clazz.getAnnotation(Test.class); //获取对应类的Test类型的注解
System.out.println(a);
if (a instanceof Test){
System.out.println(((Test)a).name()); //强制类型转型后获取name的值
System.out.println(((Test)a).age()); //强制类型转型后获取age的值
}
}
} @Retention(RetentionPolicy.RUNTIME) //保留到运行时,这条很重要
@interface Test{
public String name(); //定义两个变量
public int age();
}

重复注解

  • 重复注解是Java8新增的功能
  • 重复注解是值:用多个相同类型的注解修饰同一个程序元素
  • 使用重复注解要分3步走:
    • 定义一个注解,并用@Repeatable修饰
    • 再定义一个该注解的容器注解
    • 使用重复注解
  • 示例:
package testpack;

import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; @Test(name="C++",age=30)
@Test(name="Java",age=18) //使用了两个相同类型的注解
public class Test1 {
public static void main(String[] args){
Class clazz=Test1.class;
Annotation[] as=clazz.getAnnotations();
for (Annotation a:as){
System.out.println(a);
//输出:@testpack.Tests(value=[@testpack.Test(name=C++, age=30), @testpack.Test(name=Java, age=18)])
//其实还是只有一个注解,就是Tests这个容器注解 } }
}
@Repeatable(Tests.class) //用@Repeatable修饰
@Retention(RetentionPolicy.RUNTIME)
@interface Test{ //定义Test注解
public String name();
public int age();
}
@Retention(RetentionPolicy.RUNTIME) //容器注解的保留时间不能早于其对应的注解
@interface Tests{ //定义Test的容器注解Tests
Test[] value(); //容器注解的变量
}

类型注解

  • 类型注解也是Java8新增功能
  • Java8以前的注解只能用在一些特定的程序元素上,
  • ElementType.TYPE_PARAMETER:表示注解能写在类型变量的声明语句中
  • ElementType.TYPE_USE:表示注解能写在使用类型变量的语句中
  • 对该部分内容没什么理解,更详细的内容见:Java 8的类型注解:工具和机会

APT工具

  • APT(Annotation Processing Tool):一种注解处理工具,用于对源代码文件进行检测,找出特定的注解信息,然后进行特别的处理
  • 比如可以在编译源代码的同时,生成一些附属的描述文件,
  • 在用javac.exe编译源代码时,可以用“-processor”选项指定注解处理器
  • 注解处理器一般实现javax.annotation.processing.Processor接口或者继承AbstractProcessor抽象类
  • 一个注解处理器,可以处理一个或多个注解

其他

0035 Java学习笔记-注解的更多相关文章

  1. Java学习笔记--注解和反射

    注解和反射 1. 注解 注解作用: 对程序做出解释 被其他程序读取 注解格式: @注释名,还可以添加一些参数值,例如@SuppressWarnings(value="unchecked&qu ...

  2. Java学习笔记--注解

    注解的使用与实例:http://www.cnblogs.com/pepcod/archive/2013/02/16/2913474.html 注解的作用及使用方法:http://wenku.baidu ...

  3. 0028 Java学习笔记-面向对象-Lambda表达式

    匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...

  4. 《Java学习笔记(第8版)》学习指导

    <Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...

  5. Java学习:注解,反射,动态编译

    狂神声明 : 文章均为自己的学习笔记 , 转载一定注明出处 ; 编辑不易 , 防君子不防小人~共勉 ! Java学习:注解,反射,动态编译 Annotation 注解  什么是注解 ? Annotat ...

  6. Java学习笔记之---Servlet

    Java学习笔记之---Servlet (一)如何实现Servlet 1.实现javax.servlet.Servlet接口: 2.继承javax.servlet.GenericServlet类: 3 ...

  7. java学习笔记之基础篇

    java选择语句之switch   //switch可以用于等值判断 switch (e) //int ,或则可以自动转化成int 的类型,(byte char short)枚举jdk 7中可以防止字 ...

  8. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  9. Java学习笔记(04)

    Java学习笔记(04) 如有不对或不足的地方,请给出建议,谢谢! 一.对象 面向对象的核心:找合适的对象做合适的事情 面向对象的编程思想:尽可能的用计算机语言来描述现实生活中的事物 面向对象:侧重于 ...

随机推荐

  1. Android点击列表后弹出输入框,所点击项自动滚动到输入框上方

    使用微信的朋友圈会发现,点击某一条评论后输入框会弹出来,然后所点击的那一项会自动地滚动到输入框上方的位置,这样如果开始所点击的评论在屏幕很下方的话,就不会被输入框遮住,虽然微信这一点在我的MX2频繁点 ...

  2. 分享一个与ABP配套使用的代码生成器源码

    点这里进入ABP系列文章总目录 分享一个与ABP配套使用的代码生成器源码 真对不起关注我博客的朋友, 因最近工作很忙, 很久没有更新博客了.以前答应把自用的代码生成器源码共享出来, 也一直没有时间整理 ...

  3. IT公司的女流之辈

    声明:并不是对女性怎么怎么滴歧视, 我只是想陈述事实. 女性来IT公司工作, 真的适合吗? 如果是杰出女性也就罢了, 如果只是一般女性呢? 她能够像一般男性一样的 努力工作, 像牛马一样的工作? 在某 ...

  4. Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结

    Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结 1. 验证码的前世今生11.1. 第一代验证码 图片验证码11.2. 第二代验证码  用户操作 ,比如 ...

  5. 游戏服务器菜鸟之C#初探三游戏服务

    在经过上述2番折腾之后,最后决定使用TCP进行通信,所以在一次进行重构 主要重构的要点 1.将过来的HTPP请求,重构为TCP请求: 2.使用组件FluenScheduler进行怪物的定时刷新,和定时 ...

  6. C#:浅析结构与类的区别

    一.      结构:值类型,存储在堆栈中,位于计算机的内存逻辑区域中      类   :引用类型,存储在堆中,位于计算机内存的不同逻辑位置   二.      较小的数据使用结构:      将一 ...

  7. Hadoop的学习--安装配置与使用

    安装配置 系统:Ubuntu14.04 java:1.7.0_75 相关资料 官网 下载地址 官网文档 安装 我们需要关闭掉防火墙,命令如下: sudo ufw disable 下载2.6.5的版本, ...

  8. Java进击C#——语法之IO操作

    本章简言 上一章我们对线程同步进行讲解.了解如何去处理可能发生的脏数据.而本章就要讲有关于C#在读取IO文件的时候,常常用到的操作类.这一章的内容会比较少.但是笔者还是总结出来让读者们有一个学习的方向 ...

  9. ASP.NET Core服务器综述

    原文地址:Servers overview for ASP.NET Core By Tom Dykstra, Steve Smith, Stephen Halter, and Chris Ross A ...

  10. 【Java每日一题】20161228

    package Dec2016; import java.util.ArrayList; import java.util.List; public class Ques1228 { public s ...