我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java-Java5.0注解全面解读

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java-Java5.0注解全面解读

概述

Java5.0注解可以看做Javadoc和Xdoclet标签的延伸和发展,在Java5.0中可以自定义这些标签,并通过Java语言的反射机制获取类中标注的注解,完成特定的功能。

注解是代码的附属信息,它遵循一个基本的原则:注解不能直接干扰程序代码的运行,无论增加或者删除注解,代码都能正常运行。

Java语言解释器会忽略这些注解,而由第三方工具负责对注解进行处理。 第三方工具可以利用代码中的注解间接控制程序代码的运行,它们通过Java反射机制读取注解的信息,并根据这些信息更改目标程序的逻辑。

元注解Meta-annotation

元注解的作用就是负责注解其他注解。

Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。

Java5.0定义的元注解: 

  • - @Target
  • - @Retention
  • - @Documented
  • - @Inherited

这几个类都在java.lang.annotation包中

@Target

@Target主要说明Annotation所修饰的对象范围。

Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。

在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

作用:用于描述注解的使用范围,即被描述的注解可以用在什么地方。

取值(ElementType)有: @Target(ElementType.XXX)取值如下

  • - TYPE:类、接口、注解类、Enum声明处,相应的注解称为类型注解
  • - FIELD:类成员变量或者常量声明处,相应的注解被称为域值注解
  • - METHOD:方法处声明,相应的注解称为方法注解
  • - PARAMETER:参数声明处,相应的注解称为参数注解
  • - CONSTRUCTOR:构造函数声明处,相应的注解称为构造函数注解
  • - LOCAL_VARIABLE:局部变量声明处,相应的注解称为局域比纳凉注解
  • - PACKAGE:包声明处,相应的注解被称为包注解

举例:


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    // 和配置文件中 dynamicDatasourceMap中的key保持一致
    public static String PR_RB = "dataSourcePR";
    public static String DR_RB = "dataSourceDR";
    public static String PR_CC = "dataSourceCC";
    
    String name() default DataSource.PR_RB;
}

@Retention

@Retention定义了该Annotation被保留的时间长短.

某些Annotation仅出现在源代码中,而被编译器丢弃;

而另一些却被编译在class文件中,编译在class文件中的Annotation可能会被虚拟机忽略,

而另一些在class被装载时将被读取(并不影响class的执行,因为Annotation与class在使用上是被分离的)。

使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即被描述的注解在什么范围内有效)

Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。

这里写图片描述

取值(RetentionPoicy)有:

  • SOURCE:在源文件中有效(即源文件保留),单对应的字节码文件将不再保留
  • CLASS:在class文件中有效(即class保留),但类家爱妻加载字节码文件时不会将注解加载到JVM中,即运行期不能获取注解信息
  • RUNTIME:在运行时有效(即运行时保留),注解信息在目标类加载到JVM后依然保留,在运行期可以通过反射机制读取类中的注解信息

比如


@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    .......
}

@Documented

@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。


@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    .......
}

@Inherited

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

自定义注解

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。

在定义注解时,不能继承其他的注解或接口。

@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。

方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。

可以通过default来声明参数的默认值。

定义注解格式:


 public @interface 注解名 {定义体}

注解参数的可支持数据类型

所有基本数据类型(int,float,boolean,byte,double,char,long,short)

  • String类型
  • Class类型
  • enum类型
  • Annotation类型
  • 以上所有类型的数组

Annotation类型里面的参数设定规则:

第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;   

第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;  

第三,如果只有一个参数成员,最好把参数名称设为”value”,后加小括号.

实例

代码已托管到Github—> https://github.com/yangshangwei/SpringMaster

通常情况下,第三方工具不但负责处理特定的注解,其本身还提供了这些注解的定义。 事实上,定义注解类本身并不困难,Java提供了定义注解的语法,如上所述。

编写注解类

我们着手来编写一个简单的注解类


package com.xgj.aop.spring.advisor.anno;
import java.lang.annotation.Documented;
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.METHOD)
// 可以被javadoc此类的工具文档化
@Documented
public @interface NeedTestAnnotation { // 定义注解
    // 声明注解成员
    boolean value() default false;
}

Java新语法规定使用@interface修饰符定义注解类,一个注解可以拥有多个成员,成员声明和接口方法声明类似,这里仅仅定义了一个成员。

成员声明以下几点限制:

  • 成员以无入参,无抛出异常的方式声明, 以下方式是不合法的 比如 boolean value(String xx)、boolean value()throws Exception等是非法的
  • 可以通过default成员指定一个默认值,比如 String level() defalut “LOW_LEVEL”, int high() default 2 是合法的,当然也可以不指定默认值。
  • 成员类型是受限制的,成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;   而 List foo() 、ForumServer value()是不合法的。

如果注解只有一个成员,成员名建议为value().

在使用时可以忽略成员和赋值号(=),比如 @NeedTestAnnotation(true).

当注解类拥有多个成员时,如果仅仅对value成员进行赋值,则也可不使用赋值号。

如果同时对多个成员进行赋值,这必须使用赋值号,比如 @DecalreParents(value=”XXX”,defaultImpl=XXX).

注解类可以没有成员,没有成员的注解称为标注注解,解释程序以标识注解存在与否进行相应的处理

此外,所有的注解都隐式继承与java.lang.annotation.Annotation,但注解不允许显示继承其他的接口。

使用注解

我们在业务类中,使用NeedTestAnnotation注解,标注业务方法是否需要测试。

如下


package com.xgj.aop.spring.advisor.anno;

public class ForumService {
    @NeedTestAnnotation
    public void removeTopicId(int topicId) {
        System.out.println("remove topicId" + topicId);
    }
    @NeedTestAnnotation(true)
    public void removeForumId(int forumId) {
        System.out.println("remove forumId" + forumId);
    }
}

如果注解类和目标类不在同一个包中,这需要通过improt引用注解类。

在标注注解时,可以通过以下格式对注解成员进行赋值


@<注解名>(<成员名1>=<成员值1>,<成员名2>=<成员值2>,.....)

如果成员是数组类型,这可以通过{}进行赋值,比如 boolean数组的成员可以设置为{true,false,true}

访问注解

我们说过,注解不会直接影响程序的运行,但是第三方程序或者工具可以利用代码中的注解完成特殊的任务,间接控制程序的运行。 对于RetentionPolicy.RUNTIME保留期限的注解,可以通过反射机制访问类中的注解。

在Java5.0中,Package、Class、Constructor、Method以及Field 等反射对象都新增了访问注解信息的方法:<T extends Annotation>T getAnnotation(Class<T> annotationClass)该方法支持通过泛型直接返回注解对象.

下面通过反射来访问注解,得到ForumService类中通过@NeedTestAnnotation注解所承载的测试需求


package com.xgj.aop.spring.advisor.anno;
import java.lang.reflect.Method;
import org.junit.Test;

public class AnnotaitionSelfDefineTool {
    @Test
    public void test() {
        // 得到对应的Class
        Class<ForumService> clazz = ForumService.class;
        // 因为标注在方法上,所以先得到对应的方法
        Method[] methods = clazz.getDeclaredMethods();
        System.out.println(clazz.getName() + " 有 " + methods.length + " 个方法");
        // 遍历方法
        for (Method method : methods) {
            // 获取方法上的注解
            NeedTestAnnotation needTestAnnotation = method
                    .getAnnotation(NeedTestAnnotation.class);
            // 判断是否有标注此注解
            if (needTestAnnotation != null) {
                // 获取注解中定义的值,做处理
                if (needTestAnnotation.value()) {
                    System.out.println(method.getName() + "需要测试");
                } else {
                    System.out.println(method.getName() + "不需要测试");
                }
            }
        }
    }
}

单元测试结果:

com.xgj.aop.spring.advisor.anno.ForumService 有 2 个方法

removeTopicId不需要测试

removeForumId需要测试

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java-Java5.0注解全面解读

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java5.0中注解如何使用

这篇文章将为大家详细讲解有关Java5.0中注解如何使用,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。元注解Meta-annotation元注解的作用就是负责注解其他注解。Java5.0定义
2023-06-20

java注解的全面分析

全面解析java注解Java中的常见注解 a.JDK中的注解 @Override 覆盖父类或者父接口的方法 @Deprecated 表示方法已经过时 @SuppressWarnings("deprecation") 忽略方
2023-05-31

全面解读canvas:深入了解canvas方法的全貌

全面解读canvas:深入了解canvas方法的全貌,需要具体代码示例引言:Canvas是HTML5新增的一个标签,可以通过JavaScript脚本绘制图形、动画和其他视觉效果。它为开发者提供了一个强大的平台,可以创建各种各样的图形和视觉
全面解读canvas:深入了解canvas方法的全貌
2024-01-17

Java依赖注入容器超详细全面讲解

依赖注入(DependencyInjection)和控制反转(InversionofControl)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例
2023-01-12

阿里云服务器功能全面解读

阿里云服务器是阿里云推出的一种高性能、可扩展的计算服务,它具有多种功能,能满足各种不同场景下的需求。本文将详细介绍阿里云服务器的各种功能。一、计算能力阿里云服务器的计算能力非常强大,可以支持多种应用场景,如网站托管、应用开发、数据处理等。它的CPU和内存配置灵活,可以根据需要进行调整,满足不同的计算需求。二、存储
阿里云服务器功能全面解读
2023-12-11

Java之CountDownLatch原理全面解析

这篇文章主要介绍了Java之CountDownLatch原理解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2022-11-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录