1. 简单介绍

注解(也被称为元数据),为我们在代码中加入信息提供了一种形式化的方法。

注解在一定程度上是把元数据与源码文件结合在一起,而不是保存在外部文档中这一大趋势之下所催生的。


它能够提供用来完整的描写叙述程序所需的信息。而这些信息是无法使用Java来表达的。

因此。注解使得我们能够以将编译器来測试和验证的格式。存储有关程序的额外信息。注解能够用来生成描写叙述符文件。甚至是新的类定义。

通过使用注解。我们能够将这些元数据保存在Java源码中,并利用Annotation
API为自己的注解构造处理工具。


注解能够生成更加干净易读的代码以及编译器类型检查等等。

注解(annotation)实在实际的源码级别保存全部的信息,而不是某种凝视性文字(comment),这使得代码更加简洁。便于维护。

2. 注解分类

依照执行机制分类 描写叙述
源代码注解 注解仅仅在源代码中存在,编译成.class文件就不存在了
编译时注解 注解仅仅在源代码和.class文件里都存在(比如:@override)
执行时注解 在执行阶段还起作用,甚至影响执行逻辑的注解(比如:@Autowired)


3. 内置注解:

(1)@override

表示当前的方法定义将覆盖超类中的方法。假设你不小心拼写错误,或者方法签名对不上被覆盖的方法。编译器就会发出错误提示。


(2)@Deprecated

假设程序猿使用了注解为它的元素。那么编译器会发出警告信息。

(3)@SuppressWarnings

关闭不当的编译器警告信息(在java SE5 之前。也能够使用这个注解,只是被忽略不起作用)

4. 基本的语法

4.1 定义注解

能够看到注解的定义非常像接口的定义。

其实,与其它不论什么Java接口一样,注解也会被编译成class文件。

package com.qunar.annotation;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
public class Annotation {
// 定义Description注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
// 使用@interface keyword定义注解
public @interface Description{
// 成员以无參无异常方式声明
String desc();
String author();
// 能够使用defaultkeyword为成员指定一个默认值
int age() default 18;
}
}

除了@符号以外,@Description的定义非常像一个接口。

定义注解的时候会须要一些元注解。如@Target和@Retention。@Target用来定义你的注解将用于什么地方(是一个方法上还是一个类上),@Retention用来定义该注解在哪一个级别上可用(在源码上或者是类文件上或者是执行时)。详细以下解说。


4.2 注解元素

注解@Description中包括int元素age,以及String元素desc和author。注解元素能够使用的类型例如以下:
  • 全部基本数据类型(int,float。boolean等)
  • String
  • Class
  • enum
  • Annotation
  • 以上类型的数组
假设你使用了其它类型。那么编译器就会报错。

注意,也不同意使用不论什么包装类型。只是因为自己主动打包的存在,这算不上什么限制。注解也能够作为元素的类型。也就是注解能够嵌套。


4.3 默认值限制

编译器对元素的默认值有些过分的挑剔。

首先。元素不能有不确定的值。也就是说元素必需要么有默认值,要么使用注解时提供元素的值。
其次。对于非基本类型的元素,不管是在源码中声明时,或者是在注解接口中定义默认值时,都不能以null作为其值。为了这个约束,我们仅仅能自定义一些特殊的值,比如空字符串或者负数,来表示某个元素不存在。

4.4 元注解

元注解仅仅负责注解其它的注解。

元注解 參数 描写叙述






@Taget




CONSTRUCTOR 构造器的声明



           表示注解能够用于什么地方




FIELD 域声明
METHOD 方法声明
PACKAGE 包声明
PARAMETER 參数声明
TYPE 类,接口或enum声明
LOCAL_VARIABLE 局部变量声明  


@Retention
SOURCE 注解仅仅在源代码中存在。编译成.class文件就不存在了

        表示须要在什么级别保存该注解信息
CLASS 注解仅仅会在.class文件存在,会被VM丢弃
RUNTIME VM将在执行期也保留注解。因此能够通过反射机制读取注解的信息
@Document     将此注解包括在Javadoc中
@Inherited     同意子类继承父类中的注解


4.5 使用注解

语法:@<注解名称>(<成员名1> = <成员值1>。<成员名2> = <成员值2>。...)

package com.qunar.annotation;
 
import com.qunar.annotation.Annotation.Description;
 
public class Student {
private String name;
@Description(desc = "set name for student object" , author = "sjf0115")
public String getName() {
return name;
}
@Description(desc = "get name from student object" , author = "sjf0115", time = "2016-01-11")
public void setName(String name) {
this.name = name;
}
}


5. 解析注解

通过反射机制获取类。函数或者成员上的执行时注解信息,从而实现动态控制程序执行的逻辑。

package com.qunar.annotation;
 
import java.lang.reflect.Method;
 
import com.qunar.annotation.Annotation.Description;
 
public class ParseAnnotation {
public static void main(String[] args){
Class<? > class1 = null;
try {
// 使用类载入器载入类
class1 = Class.forName("com.qunar.annotation.Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 推断Student类上是否有Description注解
boolean isExits = class1.isAnnotationPresent(Description.class);
if(isExits){
// 注解实例
Description desc = class1.getAnnotation(Description.class);
System.out.println("注解:" + desc.toString());
}//if
// 获取Student类上的全部方法
Method[] methods = class1.getMethods();
// 遍历全部方法
for (Method method : methods) {
// 推断方法上是否有Description注解
isExits = method.isAnnotationPresent(Description.class);
if(isExits){
Description description = method.getAnnotation(Description.class);
System.out.println("方法注解:" + description.toString());
}//if
}//for
}
}
执行结果:

方法注解:@com.qunar.annotation.Annotation$Description(time=2016-01-12, desc=set name for student object, author=sjf0115)
方法注解:@com.qunar.annotation.Annotation$Description(time=2016-01-11, desc=get name from student object, author=sjf0115)

package com.qunar.annotation;
 
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
 
import com.qunar.annotation.Annotation.Description;
 
public class ParseAnnotation {
public static void main(String[] args){
Class<?> class1 = null;
try {
// 使用类载入器载入类
class1 = Class.forName("com.qunar.annotation.Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 推断Student类上是否有Description注解
boolean isExits = class1.isAnnotationPresent(Description.class);
if(isExits){
// 注解实例
Description desc = class1.getAnnotation(Description.class);
System.out.println("注解:" + desc.toString());
}//if
// 获取Student类上的全部方法
Method[] methods = class1.getMethods();
// 遍历全部方法
for (Method method : methods) {
// 方法上获取全部的注解
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
if(annotation instanceof Description){
System.out.println("Description注解:" + annotation.toString());
}//if
}//for
}//for
}
}

这两个程序都用到了反射的方法:getMethods()和getAnnotation()。它们都属于AnnotatedElement接口(Class,Method与Field等类都实现了该接口)。getAnnotation()方法返回指定类型的注解对象,在这里就是Description。假设被注解的方法上没有该类型的注解,则返回null值。


















[Java开发之路](15)注解的更多相关文章

  1. 【java开发系列】—— 自定义注解

    之前在开发中,就总纳闷,为什么继承接口时,会出现@Override注解,有时候还会提示写注解@SuppressWarnings? 原来这是java特有的特性,注解! 那么什么是注解呢? 注解就是某种注 ...

  2. Java开发学习(十)----基于注解开发定义bean 已完成

    一.环境准备 先来准备下环境: 创建一个Maven项目 pom.xml添加Spring的依赖 <dependencies>    <dependency>        < ...

  3. [Java开发之路](9)对象序列化与反序列化

    1. 对象序列化 当你创建对象时.仅仅要你须要.它会一直存在,可是程序终止时,不管何时它都不会继续存在.虽然这样做是很有意义的,可是在某些情况下.假设程序不执行时扔能存在而且保存其信息,那将对我们很实 ...

  4. [Java开发之路](16)学习log4j日志

    1. 新建一个Javaproject.导入Jar包(log4j-1.2.17.jar) Jar包下载地址:点击打开链接 2. 配置文件:创建并设置log4j.properties # 设置 log4j ...

  5. [Java 开发利器Lombok] 常用注解演示

    在以往的对象模型编码时,我们需要写一大堆的get/set以及不同的构造函数等.Lombok为我们提供了一个非常好的插件形式. 在大多数的项目中,只需要使用到以下集中Annotation就足够了,如果需 ...

  6. Java开发学习(十一)----基于注解开发bean作用范围与生命周期管理

    一.注解开发bean作用范围与生命周期管理 前面使用注解已经完成了bean的管理,接下来将通过配置实现的内容都换成对应的注解实现,包含两部分内容:bean作用范围和bean生命周期. 1.1 环境准备 ...

  7. Java开发学习(十三)----基于注解开发定义第三方bean及注解开发总结

    在前面的博客中定义bean的时候都是在自己开发的类上面写个注解就完成了,但如果是第三方的类,这些类都是在jar包中,我们没有办法在类上面添加注解,这个时候该怎么办? 遇到上述问题,我们就需要有一种更加 ...

  8. [Java开发之路](8)输入流和输出流

    1. Java流的分类 按流向分: 输入流: 能够从当中读入一个字节序列的对象称作输入流. 输出流: 能够向当中写入一个字节序列的对象称作输出流. 这些字节序列的来源地和目的地能够是文件,并且通常都是 ...

  9. [Java开发之路](23)装箱与拆箱

    1. 简单介绍 大家对基本数据类型都很熟悉.比如 int.float.double.boolean.char 等.基本数据类型是不具备对象的特性,比方基本类型不能调用方法.功能简单. ..,为了让基本 ...

随机推荐

  1. thinkphp验证码(总结之后,效率非常好)

    thinkphp验证码(总结之后,效率非常好) 一.总结 1.总结:总结之后,效率非常好,复习的时候也才方便,也能深入到细处,非常方便建立熟悉感和突破使用困境 2.验证码使用中文集或者繁体集设置:这个 ...

  2. 在Qt Creator的项目中添加头文件和库

    在Qt Creator中的工程中,工程通过.pro文件管理. 额外需要连接的连接库unix:LIBS += -L your_lib_path -lyour_libwin32:LIBS += your_ ...

  3. C#中流,字节,字符,字符串

    首先要明白它们本身是由什么组成的: 流:二进制 字节:无符号整数 字符:Unicode编码字符 字符串:多个Unicode编码字符 那么在.net下它们之间如何转化呢? 一般是遵守以下规则: 流-&g ...

  4. AJAX - 封装的传参改为传入对象 XML JSON 数据格式

    Ajax封装函数,上次是直接传参,这次在原来的基础上改进,模仿jQuery 直接传入对象,把之前的参数都变为这个对象的属性. 这样可以随意调换传入数据的次序. 其他优点? 需要再复习一下. Ajax处 ...

  5. 八、Docker+RabbitMQ

    原文:八.Docker+RabbitMQ 一.下载镜像 docker pull rabbitmq:management 二.运行 docker run -d --name rabbitmq -e TZ ...

  6. Servlet 规范笔记—基于http协议的servlet

    在上一章节,我们大概的描述了servlet的规范以及servlet和servlet容器的概念和用途,我们清楚的知道servlet容器提供了接收来自client端的请求,然后根据请求进行处理(如:执行对 ...

  7. Lightoj 1043 - Triangle Partitioning【二分】

    题目链接:http://lightoj.com/volume_showproblem.php? problem=1043 题意:一个三角形ABC,DE//BC.已知三角形ADE和四边形BDEC的面积的 ...

  8. Linux 解压缩命令整理

    一.tar命令 参数 参数 详解 参数 详解 -c 可以使用绝对路径来压缩 -x 解开一个压缩文件的参数指令 -t 查看内容 -r 向压缩归档文件末尾追加文件 -u 更新原压缩包中的文件 -z 有gz ...

  9. 1.1 Introduction中 Kafka as a Storage System官网剖析(博主推荐)

    不多说,直接上干货! 一切来源于官网 http://kafka.apache.org/documentation/ Kafka as a Storage System kafka作为一个存储系统 An ...

  10. JS学习笔记 - fgm练习 - 限制输入框的字符类型 正则 和 || 或运算符的运用 i++和++i

    <script> window.onload = function(){ var aInp = document.getElementsByTagName('input'); var oS ...