注解的产生背景
以前,xml以低耦合的方式得到了广大开发者的青睐,xml在当时基本上能完成框架中的所有配置。但是随着项目越来越庞大,xml的配置也越来越复杂,维护性也随之降低,维护成本增高。于是就产生了一种标记式的高耦合的配置方式——注解。

注解的本质
注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记,由java编译器来解析,标记可以加在包、类,属性、方法,方法的参数以及局部变量上。本质就是一个继承了 Annotation 接口的接口。

注解的解析方式
有两种方式:

  1. 编译期直接扫描:编译器在对 java 代码编译字节码的过程中会检测到某个类或者方法被一些注解修饰,这时它就会对于这些注解进行某些处理,只适用于那些编译器已经熟知的注解类。
  2. 运行时反射

典型的就是注解 @Override,一旦编译器检测到某个方法被修饰了 @Override 注解,编译器就会检查当前方法的方法签名是否真正重写了父类的某个方法,也就是比较父类中是否具有一个同样的方法签名。

元注解

  • @Target:注解的作用目标
  • @Retention:注解的生命周期
  • @Documented:注解是否应当被包含在 JavaDoc 文档中
  • @Inherited:是否允许子类继承该注解

@Target:
用于指明被修饰的注解最终可以作用的目标是谁,也就是指明,你的注解到底是用来修饰方法的、修饰类的、还是用来修饰字段属性的?
@Target 的定义如下:

我们可以通过以下的方式来为这个 value 传值:

@Target(value = {ElementType.FIELD})

被 @Target 注解修饰的注解将只能作用在成员字段上,不能用于修饰方法或者类。其中,ElementType 是一个枚举类型,有以下一些值:

  • ElementType.TYPE:允许被修饰的注解作用在类、接口和枚举上
  • ElementType.FIELD:允许作用在属性字段上
  • ElementType.METHOD:允许作用在方法上
  • ElementType.PARAMETER:允许作用在方法参数上
  • ElementType.CONSTRUCTOR:允许作用在构造器上
  • ElementType.LOCAL_VARIABLE:允许作用在本地局部变量上
  • ElementType.ANNOTATION_TYPE:允许作用在注解上
  • ElementType.PACKAGE:允许作用在包上

@Retention:
用于指明当前注解的生命周期。
它的基本定义如下:

同样的,它也有一个 value 属性:

@Retention(value = RetentionPolicy.RUNTIME

这里的 RetentionPolicy 依然是一个枚举类型,它有以下几个枚举值可取:

  • RetentionPolicy.SOURCE:当前注解编译期可见,不会写入 class 文件
  • RetentionPolicy.CLASS:类加载阶段丢弃,会写入 class 文件
  • RetentionPolicy.RUNTIME:永久保存,可以反射获取

@Retention注解指定了被修饰的注解的生命周期,一种是只能在编译期可见,编译后会被丢弃,一种会被编译器编译进 class 文件中,无论是类或是方法,乃至字段,他们都是有属性表的,而 JAVA 虚拟机也定义了几种注解属性表用于存储注解信息,但是这种可见性不能带到方法区,类加载时会予以丢弃,最后一种则是永久存在的可见性。

@Documented:
当我们执行 JavaDoc 文档打包时会被保存进 doc 文档,反之将在打包时丢弃。

@Inherited:
具有可继承性的,也就说我们的注解修饰了一个类,而该类的子类将自动继承父类的该注解。

Java内置三大注解:

  • @Deprecated 意思是“废弃的,过时的”
  • @Override 意思是“重写、覆盖”
  • @SuppressWarnings 意思是“压缩警告”

@Override
它的定义如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

它没有任何的属性,所以并不能存储任何其他信息。它只能作用于方法之上,编译结束后将被丢弃。
所以它就是一种典型的标记式注解,仅被编译器可知,编译器在对 java 文件进行编译成字节码的过程中,一旦检测到某个方法上被修饰了该注解,就会去匹对父类中是否具有一个同样方法签名的函数,如果不是,自然不能通过编译。

@Deprecated
它的基本定义如下:

依然是一种标记式注解,永久存在,可以修饰所有的类型,作用是标记当前的类或者方法或者字段等已经不再被推荐使用了,可能下一次的 JDK 版本就会删除。

但是,编译器并不会强制要求你做什么,只是告诉你 JDK 已经不再推荐使用当前的方法或者类了,建议你使用某个替代者。

@SuppressWarnings
主要用来压制 java 的警告,它的基本定义如下:

它有一个 value 属性需要你主动的传值,这个 value 代表的就是需要被压制的警告类型。例如:

public static void main(String[] args) {
Date date = new Date(2018, 7, 11);
}

这么一段代码,程序启动时编译器会报一个警告。

Warning:(8, 21) java: java.util.Date 中的 Date(int,int,int) 已过时

而如果我们不希望程序启动时,编译器检查代码中过时的方法,就可以使用 @SuppressWarnings 注解并给它的 value 属性传入一个参数值来压制编译器的检查。

@SuppressWarning(value = "deprecated")
public static void main(String[] args) {
Date date = new Date(2018, 7, 11);
}

这样你就会发现,编译器不再检查 main 方法下是否有过时的方法调用,也就压制了编译器对于这种警告的检查。

自定义注解

package com.test.Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation {
}

  

package com.test.Annotation;

@MyAnnotation
public class AnnotationTest {
public static void main(String[] args) {
if (AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = (MyAnnotation) AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(annotation); //结果:@com.test.Annotation.MyAnnotation()
}
}
}

为注解添加属性
1.添加属性
语法:类型 属性名();

package com.test.Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation {
String str();
}

  

package com.test.Annotation;

@MyAnnotation(str="abc")
public class AnnotationTest {
public static void main(String[] args) {
if (AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = (MyAnnotation) AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(annotation.str()); //结果:abc
}
}
}

  

2.为属性指定缺省值(默认值)
语法:类型 属性名() default 默认值;

package com.test.Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation {
String str() default "aaa";
}

  

package com.test.Annotation;

@MyAnnotation
public class AnnotationTest {
public static void main(String[] args) {
if (AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = (MyAnnotation) AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(annotation.str());//结果:aaa
}
}
}

  

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

package com.test.Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation {
String str() default "aaa";
String value();
}

  

package com.test.Annotation;

@MyAnnotation("bbb")
public class AnnotationTest {
public static void main(String[] args) {
if (AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = (MyAnnotation) AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(annotation.str() + " " + annotation.value());
} //结果:aaa bbb
}
}

  

4.添加高级属性
(1)数组类型的属性

  • 增加数组类型的属性:int[] array() default {1,2,4};
  • 应用数组类型的属性:@MyAnnotation(array={2,4,5})
  • 如果数组属性只有一个值,这时候属性值部分可以省略大括号,如:@MyAnnotation(array=2),这就表示数组属性只有一个值,值为2

(2)枚举类型的属性

  • 增加枚举类型的属性:EumTrafficLamp lamp() default EumTrafficLamp.Red;
  • 应用枚举类型的属性:@MyAnnotation(lamp=EumTrafficLamp.Green)

(3)注解类型的属性

  • 为注解添加一个注解类型的属性,并指定注解属性的缺省值:MetaAnnotation meta() default @MetaAnnotation("uvw");

注解综合示例
EumTrafficLamp:

package com.test.Annotation;

public enum EumTrafficLamp {
Red,
Yellow,
Black,
White,
}

MetaAnnotation:

package com.test.Annotation;

public @interface MetaAnnotation {
String value();
}

MyAnnotation1:

package com.test.Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation1 {
String color() default "Green"; String value(); int[] array() default { 1, 2, 3, 4 }; EumTrafficLamp lamp() default EumTrafficLamp.Black; MetaAnnotation meta() default @MetaAnnotation("uvw");
}

MyAnnotationTest:

package com.test.Annotation;

@MyAnnotation1(color = "Red",
value = "abc",
array = { 5, 6, 7,8 },
lamp = EumTrafficLamp.White,
meta = @MetaAnnotation("xyz")
)
public class MyAnnotationTest {
public static void main(String[] args) {
if (MyAnnotationTest.class.isAnnotationPresent(MyAnnotation1.class)) {
MyAnnotation1 annotation = MyAnnotationTest.class.getAnnotation(MyAnnotation1.class);
System.out.println(annotation.color());
System.out.println(annotation.value());
for (int num : annotation.array()) {
System.out.print(num + " ");
}
System.out.println();
System.out.println(annotation.lamp());
System.out.println(annotation.meta().value());
MetaAnnotation meta = annotation.meta();
System.out.println(meta);
}
}
}
//输出结果:
//Red
//abc
//5 6 7 8
//White
//xyz
//@com.test.Annotation.MetaAnnotation(value=xyz)

Java——注解的更多相关文章

  1. Java注解

    Java注解其实是代码里的特殊标记,使用其他工具可以对其进行处理.注解是一种元数据,起到了描述.配置的作用,生成文档,所有的注解都隐式地扩展自java.lang.annotation.Annotati ...

  2. 19.Java 注解

    19.Java注解 1.Java内置注解----注解代码 @Deprecated                                    //不推荐使用的过时方法 @Deprecated ...

  3. Java注解入门

    注解的分类   按运行机制分:   源码注解:只在源码中存在,编译后不存在 编译时注解:源码和编译后的class文件都存在(如@Override,@Deprecated,@SuppressWarnin ...

  4. java注解(Annotation)解析

    注解(Annotation)在java中应用非常广泛.它既能帮助我们在编码中减少错误,(比如最常见的Override注解),还可以帮助我们减少各种xml文件的配置,比如定义AOP切面用@AspectJ ...

  5. JAVA 注解的几大作用及使用方法详解

    JAVA 注解的几大作用及使用方法详解 (2013-01-22 15:13:04) 转载▼ 标签: java 注解 杂谈 分类: Java java 注解,从名字上看是注释,解释.但功能却不仅仅是注释 ...

  6. attilax.java 注解的本质and 使用最佳实践(3)O7

    attilax.java 注解的本质and 使用最佳实践(3)O7 1. 定义pojo 1 2. 建立注解By eclipse tps 1 3. 注解参数的可支持数据类型: 2 4. 注解处理器 2 ...

  7. paip.java 注解的详细使用代码

    paip.java 注解的详细使用代码 作者Attilax 艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.net/att ...

  8. JAVA 注解的几大作用及使用方法详解【转】

    java 注解,从名字上看是注释,解释.但功能却不仅仅是注释那么简单.注解(Annotation) 为我们在代码中添加信息提供了一种形式化的方法,是我们可以在稍后 某个时刻方便地使用这些数据(通过 解 ...

  9. 框架基础——全面解析Java注解

    为什么学习注解? 学习注解有什么好处? 学完能做什么? 答:1. 能够读懂别人写的代码,特别是框架相关的代码: 2. 让编程更加简洁,代码更加清晰: 3. 让别人高看一眼. spring.mybati ...

  10. Java注解配置

    Java注解是附加在代码中的一些元信息,用于一些工具在编译.运行时进行解析和使用,起到说明.配置的功能.注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用.包含在 java.lang.annota ...

随机推荐

  1. Laravel 配置 SqlDebug 服务,进行实时监听打印 SQL

    0:释义 什么是服务容器 简而言之,Laravel 服务容器 是一个用于存储绑定组件的盒子,它还会为应用提供所需的服务. Laravel 服务容器是用于管理类的依赖和执行依赖注入的工具,By Lara ...

  2. odoo本地pycham环境搭建(mac)

    本文以odoo12为例配置本地环境,注意不是docker环境 1.安装pycharm(推荐2020.1版本,破解地址:https://www.cnblogs.com/xuexianqi/p/12767 ...

  3. “商家参数格式有误”应用切微信H5支付完美解决方案

    一.业务场景发生 最近在跟一些合作公司作业务对接,在对方的APP中接入我们的H5支付,包括微信和支付宝. 那就开搞,进展顺利,貌似一切都在掌握之中,给到对方一个链接即可调起支付.形如: https:/ ...

  4. Python自动化运维 技术与最佳实践PDF高清完整版免费下载|百度云盘|Python基础教程免费电子书

    点击获取提取码:7bl4 一.内容简介 <python自动化运维:技术与最佳实践>一书在中国运维领域将有"划时代"的重要意义:一方面,这是国内第一本从纵.深和实践角度探 ...

  5. windows 下部署 .netcore 到 windows service

    接上一篇 <windows 下部署 .netcore 到 iis>,这一篇记录一下怎么将 Asp.Net Core 以 windows 服务的方式部署. 一.修改代码 其实也很简单,只要调 ...

  6. 如何利用NLog输出结构化日志,并在Kibana优雅分析日志?

    上文我们演示了使用NLog向ElasticSearch写日志的基本过程(输出的是普通文本日志),今天我们来看下如何向ES输出结构化日志.并利用Kibana中分析日志. NLog输出结构化日志 Elas ...

  7. Windows聚焦失效问题的解决办法

    1. 设置Windows聚焦 步骤:任务栏右键 → 任务栏设置 → 锁屏界面 → 背景选择Windows聚焦 2. 解决Windows聚焦失效问题 设置完Windows聚焦之后,锁屏界面却没有变. 尝 ...

  8. 微信公众号添加word文件

    微信公众号添加word文件的教程 我们都知道创建一个微信公众号,在公众号中发布一些文章是非常简单的,但公众号添加附件下载的功能却被限制,如今可以使用小程序“微附件”进行在公众号中添加附件. 以下是公众 ...

  9. 静态集成腾讯TBS X5内核WebView,从微信提取新版30M浏览器内核打包进apk

    目录 前情提要 第一步:下载老版本SDK得到jar 获取SDK 集成SDK 步骤二.下载提取最新TBS X5内核 方法1:从微信中提取 方法2:App内内访问tbs调试页安装新内核 步骤三.集成内核到 ...

  10. 2020-06-02:千万级数据量的list找一个数据。

    福哥答案2020-06-02: 对于千万级长度的数组单值查找:序号小的,单线程占明显优势:序号大的,多线程占明显优势.单线程时间不稳定,多线程时间稳定. go语言测试代码如下: package mai ...