Java自定义注解的定义与使用

news/2024/11/13 3:36:56/

什么是注解?

对于很多初次接触的开发者来说应该都有这个疑问?

Annontation是Java5开始引入的新特征,中文名称叫注解。

它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。

为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。

Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。

Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。

注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。

注解的用处:

1、生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等

2、跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2 依赖注入,未来java 开发,将大量注解配置,具有很大用处;

3、在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

4、配合反射完成一些功能,这才是核心

注解的原理:

注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。

而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。

通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法。

该方法会从memberValues这个Map 中索引出对应的值。

而memberValues 的来源是Java 常量池。

元注解:

java.lang.annotation 提供了四种元注解,专门注解其他的注解(在自定义注解的时候,需要使用到元注解):

@Documented – 注解是否将包含在JavaDoc中 一般直接写上 类似于说明

@Retention – 什么时候使用该注解 何时?

@Target – 注解用于什么地方 何地?

@Inherited – 是否允许子类继承该注解 一般不用…

具体属性值

1.)@Retention – 定义该注解的生命周期

● RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。

● RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式

● RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。

2.)Target – 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地方。可用的ElementType 参数包括

● ElementType.CONSTRUCTOR: 用于描述构造器

● ElementType.FIELD: 成员变量、对象、属性(包括enum实例)

● ElementType.LOCAL_VARIABLE: 用于描述局部变量

● ElementType.METHOD: 用于描述方法

● ElementType.PACKAGE: 用于描述包

● ElementType.PARAMETER: 用于描述参数

● ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明

3.)@Documented – 一个简单的Annotations 标记注解,表示是否将注解信息添加在java 文档中。

4.)@Inherited – 定义该注释和子类的关系

@Inherited 元注解是一个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。

如果一个使用了@Inherited 修饰的annotation 类型被用于一个class,则这个annotation 将被用于该class 的子类。

常见标准的Annotation:

1.)Override

java.lang.Override 是一个标记类型注解,它被用作标注方法。它说明了被标注的方法重写了父类的方法,起到了断言的作用。如果我们使用了这种注解在一个没有覆盖父类方法的方法时,java 编译器将以一个编译错误来警示。

2.)Deprecated

Deprecated 也是一种标记类型注解。当一个类型或者类型成员使用@Deprecated 修饰的话,编译器将不鼓励使用这个被标注的程序元素。所以使用这种修饰具有一定的“延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为@Deprecated,但编译器仍然要报警。

3.)SuppressWarnings

SuppressWarning 不是一个标记类型注解。它有一个类型为String[] 的成员,这个成员的值为被禁止的警告名。对于javac 编译器来讲,被-Xlint 选项有效的警告名也同样对@SuppressWarings 有效,同时编译器忽略掉无法识别的警告名。

  @SuppressWarnings(“unchecked”)

常用注解

  在日常编程中,我们遇到的注解有@Override、@SuppressWarnings等等,@Override表示重写父类的方法,@SuppressWarnings表示忽略警告信息。

用法如下:

package com.ares.Temp;/*** @author Ares*/
public class T {@SuppressWarnings("unused")public static void test(){int i;System.out.println("This is a test.");}@Overridepublic String toString(){return "Test Class";}}

自定义注解:

自定义注解类编写的一些规则:

  1. Annotation 型定义为@interface, 所有的Annotation 会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口.

  1. 参数成员只能用public 或默认(default) 这两个访问权修饰 默认是value() 可以省略

  1. 参数成员只能用基本类型byte、short、char、int、long、float、double、boolean八种基本数据类型和String、Enum、Class、annotations等数据类型,以及这一些类型的数组.

  1. 要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation 对象,因为你除此之外没有别的获取注解对象的方法

  1. 注解也可以没有定义成员,不过这样注解就没啥用了
    6.自定义注解需要使用到元注解否则无法确认哪里 何时

package com.annotation.test;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitColor {enum Color{RED,YELLOW,WHITE}Color fruitColor() default Color.RED;}

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitName {String value() default "";}
package com.annotation.test;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FruitProvider {int id() default 0;String user() default "";String address() default "";}

以上是定义的苹果的相关信息,下面,我們开始使用上面定义的注解来进行具体的实现:

package com.annotation.test;import com.annotation.test.FruitColor.Color;public class Apple {@FruitName(value="FuShi Apple")private String fruitName;@FruitColor(fruitColor=Color.RED)private String fruitColor;@FruitProvider(id=1,user="Tom",address="China")private FruitProvider provider;
}

上面的Apple类是使用我们自己定义的注解来对类成员进行修饰。接下來,我们获取我们的注释信息:

package com.annotation.test;2 3 import java.lang.reflect.Field;4 5 public class Test {6 7     8     public static void getFruitInfo(String clas){9         try {
10             Class<?> cls = Class.forName(clas);
11             Field[] fields = cls.getDeclaredFields();
12             
13             for (Field field : fields) {
14                 if(field.isAnnotationPresent(FruitName.class)==true){
15                     FruitName name = field.getAnnotation(FruitName.class);
16                     System.out.println("Fruit Name:"+name.value());
17                 }
18                 if(field.isAnnotationPresent(FruitColor.class)){
19                     FruitColor color = field.getAnnotation(FruitColor.class);
20                     System.out.println("Fruit Color:"+color.fruitColor());
21                 }
22                 if(field.isAnnotationPresent(FruitProvider.class)){
23                     FruitProvider Provider = field.getAnnotation(FruitProvider.class);
24                     System.out.println("Fruit FruitProvider: ProviderID:"+Provider.id()+" Provider:"+Provider.user() +" ProviderAddress:"+Provider.address());
25                 }
26             }
27             
28             
29         } catch (ClassNotFoundException e) {
30             e.printStackTrace();
31         }
32     }
33     
34     public static void main(String[] args) {
35         getFruitInfo("com.annotation.test.Apple");
36     }
37     
38 }

输出结果为:

Fruit Name:FuShi Apple
Fruit Color:RED
Fruit FruitProvider: ProviderID:1 Provider:Tom ProviderAddress:China

http://www.ppmy.cn/news/36555.html

相关文章

6自由度串联机械臂实现电磁铁搬运功能

1. 功能描述 R323样机是一款拥有6自由度的串联机械臂。本文提供的示例所实现的功能为&#xff1a;在6自由度串联机械臂样机上安装电磁铁&#xff0c;底座上安装近红外传感器&#xff0c;当检测到有物品时&#xff0c;实现机械臂电磁铁搬运物品的功能。 ​ 2. 电子硬件 在这个示…

vue项目使用Print.js插件实现PDF文件打印

一&#xff0c;Print.js介绍 Print.js主要是为了帮助我们在应用程序中直接打印PDF文件&#xff0c;而不需要离开界面&#xff0c;也不需要使用嵌入。对于用户不需要打开或下载PDF文件的特殊情况&#xff0c;只需要打印即可。 例如&#xff0c;当用户请求打印在服务器端生成的报…

如何把ntfs改成苹果电脑使用及mac写入ntfs硬盘软件教程

ntfs是一种功能强大的文件系统&#xff0c;该格式的文件系统具有存储空间大&#xff0c;传输单个文件能力强&#xff0c;安全系数高等诸多优点&#xff0c;被广泛应用在移动硬盘中。但ntfs格式硬盘&#xff0c;不能在mac中被正常读写&#xff0c;那么ntfs怎么在mac使用&#xf…

leetcode 汉诺塔问题(面试题)

题目 在经典汉诺塔问题中&#xff0c;有 3 根柱子及 N 个不同大小的穿孔圆盘&#xff0c;盘子可以滑入任意一根柱子。一开始&#xff0c;所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制: (1) 每次只能移动一个盘子;…

Matplotlib库基础图表函数及引力波的绘制实例

pyplot基本图表函数概述 pyplot饼图的绘制 plt.pie() lables指的是饼图的标签 sizes指的是对应的尺寸 explode让第二个30%突出0.1 autopct中间显示百分数的方式 shadowFalse二维饼图不带阴影 startangle90饼图的起始角度 加plt.axis(equal)可以让饼图成为一个正圆形的饼图…

Tomcat学习之源码模块

Tomcat核心模块剖析 Tomcat是一款流行的开源Servlet容器&#xff0c;它提供了一个Web应用程序的运行环境。Tomcat的核心模块可以分为以下几个方面&#xff1a; Catalina&#xff1a; Catalina是Tomcat的核心组件之一&#xff0c;它负责管理Tomcat的生命周期和处理请求。Cata…

【Python】照片居然能变素描?不会画画但是咱会代码

文章目录前言一、准备二、下载预训练模型总结前言 Photo-Sketching 一个能将照片的轮廓识别出来并将其转化为“速写”型图像的开源模块。 比如&#xff0c;这只小狗&#xff1a; 经过模型的转化&#xff0c;会变成卡通版的小狗&#xff1a; 非常秀&#xff0c;这很人工智能…

基于Python的高光谱图像分析教程

1、前言超光谱图像 (HSI) 分析因其在从农业到监控的各个领域的应用而成为人工智能 (AI) 研究的前沿领域之一。 该领域正在发表许多研究论文&#xff0c;这使它变得更加有趣&#xff01; 和“对于初学者来说&#xff0c;在 HSI 上开始模式识别和机器学习是相当麻烦的”&#xff…