Java注解(Annotation)的学习

文章目录

  • 注解定义
  • 作用分类
  • API 文档注解
  • JDK 预定义的注解
  • 自定义注解
    • 注解的格式
    • 注解的本质
    • 注解的属性
      • 属性的返回值类型
      • 属性的特点
      • 属性的赋值
    • 元注解
      • @Target
      • @Retention
      • @Documented
      • @Inherited
  • 解析注解
  • 总结

注解定义

注解( Annotation),也叫元数据。一种代码级别的说明。它是 JDK1.5 及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

注解的叫法很多:元数据、标签、标记…

使用注解的叫法很多:使用xxx注解标注、使用xxx注解标记、使用xxx注解描述…

作用分类

①编写文档:通过代码里标识的元数据生成文档
编写程序时以一套特定的标签(即注解)作注释,在程序编写完成后,通过 Javadoc 就可以同时形成程序的开发文档了。

②代码分析:通过代码里标识的元数据对代码进行分析
使用反射技术,获取注解属性的值,然后处理有关的业务逻辑

③编译检査:通过代码里标识的元数据让编译器能够实现基本的编译检查
例如:@Override 注解,就可以检测被注解的方法是否正确覆盖重写父类的方法。

API 文档注解

演示代码:

package priv.lwx.javaprac.annotation;/*** 生成文档(javadoc)的注解演示代码** @author liaowenxiong* @date 2021/9/16 下午3:58* @since JDK 1.5*/
public class Demo01Annotation {public static void main(String[] args) {}/*** 计算两个整数的和* @param a 整数* @param b 整数* @return 两个整数的和*/public int add(int a, int b) {return a + b;}
}

如上的演示代码,在注释中有很多的 @xxx,这些就是文档注解,可以将这些注解的内容提取成为 API 文档。

关于如何编写文档注解,以及如何生成 javadoc 请参见《JDK 命令之 javadoc – 生成API文档》。

JDK 预定义的注解

@Override
用来检查被该注解标注的方法是不是有效的方法重写。在方法签名相同的情况下覆盖重写父类的方法,在其它地方如果有问题,会直接报编译错误,无需该注解来检测。只有方法签名不同的情况下,而又希望覆盖重写父类的方法,使用该注解检测才有意义。那么什么情况下会出现这个问题,那么就是父类方法的参数很多,确实容易写错,而你的本意又确实是重写父类的方法,那么此时使用此注解就可以帮到你了。

@Deprecated
用来表明被该注解标注的类成员已经过时,如果标注的是方法则会在方法名上显示一条“删除线”

@SuppressWarnings
抑制警告,禁止警告
注:一般传递参数“all”

@SuppressWarnings("all")
public void test() {show();
}

自定义注解

可以通过反编译来查看注解实际的代码。
例如,查看注解 @Deprecated 的实际代码,你需要先编译它的源代码,再反编译字节码文件才能看到。

@Deprecated 注解的源代码如下:

package java.lang;import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;/*** A program element annotated {@code @Deprecated} is one that programmers* are discouraged from using. An element may be deprecated for any of several* reasons, for example, its usage is likely to lead to errors; it may* be changed incompatibly or removed in a future version; it has been* superseded by a newer, usually preferable alternative; or it is obsolete.** <p>Compilers issue warnings when a deprecated program element is used or* overridden in non-deprecated code. Use of the {@code @Deprecated}* annotation on a local variable declaration or on a parameter declaration* or a package declaration has no effect on the warnings issued by a compiler.** <p>When a module is deprecated, the use of that module in {@code* requires}, but not in {@code exports} or {@code opens} clauses causes* a warning to be issued. A module being deprecated does <em>not</em> cause* warnings to be issued for uses of types within the module.** <p>This annotation type has a string-valued element {@code since}. The value* of this element indicates the version in which the annotated program element* was first deprecated.** <p>This annotation type has a boolean-valued element {@code forRemoval}.* A value of {@code true} indicates intent to remove the annotated program* element in a future version. A value of {@code false} indicates that use of* the annotated program element is discouraged, but at the time the program* element was annotated, there was no specific intent to remove it.** @apiNote* It is strongly recommended that the reason for deprecating a program element* be explained in the documentation, using the {@code @deprecated}* javadoc tag. The documentation should also suggest and link to a* recommended replacement API, if applicable. A replacement API often* has subtly different semantics, so such issues should be discussed as* well.** <p>It is recommended that a {@code since} value be provided with all newly* annotated program elements. Note that {@code since} cannot be mandatory,* as there are many existing annotations that lack this element value.** <p>There is no defined order among annotation elements. As a matter of* style, the {@code since} element should be placed first.** <p>The {@code @Deprecated} annotation should always be present if* the {@code @deprecated} javadoc tag is present, and vice-versa.** @author  Neal Gafter* @since 1.5* @jls 9.6.4.6 @Deprecated*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
public @interface Deprecated {/*** Returns the version in which the annotated element became deprecated.* The version string is in the same format and namespace as the value of* the {@code @since} javadoc tag. The default value is the empty* string.** @return the version string* @since 9*/String since() default "";/*** Indicates whether the annotated element is subject to removal in a* future version. The default value is {@code false}.** @return whether the element is subject to removal* @since 9*/boolean forRemoval() default false;
}

把这份源代码文件复制到其它地方,使用命令编译和反编译,命令如下:

liaowenongdeair:test liaowenxiong$ javac Deprecated.java # 先编译源代码
liaowenongdeair:test liaowenxiong$ javap Deprecated.class # 反编译字节码文件
Compiled from "Deprecated.java"
public interface Deprecated extends java.lang.annotation.Annotation {public abstract java.lang.String since();public abstract boolean forRemoval();
}
liaowenongdeair:test liaowenxiong$ 

注解的格式

元注解
public @interface 注解名称 {属性列表(本质就是抽象方法)
}

注解的本质

注解本质就是接口,继承自父接口 Annotation

注解的属性

所谓“属性”就是注解接口体(即大括号 {})中声明的常量和方法。所以“属性”的本质就是抽象方法。声明了属性则使用注解时必须给属性赋值。

为什么将方法称之为属性,看下面的示例代码:

// 使用自定义的注解
@MyAnno1(name = "李瓶儿") // 其中name是注解声明的抽象方法名,使用注解时需要赋值,赋值语法格式类似属性赋值的格式,所以将注解中声明的抽象方法称为"属性"
public void test() {show();
}

属性的返回值类型

返回值类型:
1.基本数据类型
2.String
3.枚举
4.注解
5.以上类型的数组

除了以上五种,其它类型不能作为注解接口中声明的抽象方法的返回值类型。

属性的特点

1.属性的默认值:在声明注解的属性时,如果使用关键字 default 给属性默认值,则使用注解时可以不进行属性的赋值,会取默认值。

2.在使用注解时,如果只有一个属性,且属性名称为 value,那么在给该属性赋值时,可以省略属性名称,即本来要 这么写 @MyAnno1(value = "李瓶儿"),可以省略成 @MyAnno1("李瓶儿")

3.注解类中声明的抽象方法名,返回值是字符串数组,那么给属性赋值时,如果多个值使用大括号包裹,如果只有一个值,则可以省略大括号。

声明定义注解及属性示例代码:

package priv.lwx.javaprac.annotation;/*** 自定义注解** @author liaowenxiong* @date 2021/9/20 下午5:18*/
public @interface MyAnno1 {String name(); // 这是抽象方法,在注解中可以称为属性,使用此注解时,需要赋值,赋值格式:name = 一个字符串int age() default 12; // 默认值12,在使用注解时,没有指定该属性,那么该属性的默认值就是12
}

属性的赋值

各种返回值类型的属性如何赋值,请看下面的示例代码:

@MyAnno1(name = "高圆圆", setColor = Color.C1, test = @MyAnno2, names = {"双儿", "小栗子"})
/* 
name方法的返回值是字符串,所以赋值字符串;setColor方法的返回值是枚举类,所以赋值时取枚举值,类似类的静态常量test方法的返回值是注解类,所以赋值时格式为 @注解类名称names是注解类中声明的抽象方法名,返回值是字符串数组,那么给属性names赋值时,
如果多个值使用大括号包裹,如果只有一个值,则可以省略大括号。
*/
public void test() {show();
}

元注解

用于描述注解的注解。

@Target

描述注解可以作用的位置

@Target(value={ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PACKAGE, ElementType.MODULE, ElementType.PARAMETER, ElementType.TYPE})
public @interface MyAnno3 {
}

如上示例,表示被描述的注解(MyAnno3)可以作用于构造器、字段、局部变量、方法、包、模块、参数、类上。{} 内的都是枚举类 ElementType 的枚举值。

@Retention

描述注解被保留的阶段(源码阶段、编译阶段、运行时阶段)

有三个值:
SOURCE:被描述的注解仅在源码阶段保留,编译时就被舍弃了
CLASS:被描述的注解会保留到字节码文件中,类加载进内存时被舍弃了
RUNTIME:被描述的注解会保留到运行时阶段,即类加载进入内存时,注解也会被加载进内存,可以通过反射获取相关信息

@Documented

描述注解是否可以被 javadoc 抽取到文档中,即被描述的注解会原样出现在API文档中

@Inherited

描述注解是否被子类继承

解析注解

获取注解属性中定义的值。
本质:就是获取注解类的实例对象,然后调用注解属性对应的成员方法,获得对应的返回值

步骤:
1.获得被注解的类/方法/字段对应的反射对象,即类就是 Class 对象,方法就是 Method 对象,变量就是 Field 对象
2.通过反射对象获得注解的实例对象,即调用反射对象的 getAnnotation/getAnnotations 等方法获取注解对象
3.调用注解对象的方法,获得返回值,该返回值就是对应注解属性中定义的值

演示代码:

package priv.lwx.javaprac.annotation;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;/*** 该类可以创建任意类型的对象,执行其中的任意方法.** 使用注解的方式取代属性文件的方式来获取类名和方法名.* @author liaowenxiong* @date 2021/9/21 上午7:49*/
@Pro(className = "priv.lwx.javaprac.annotation.Person", methodName = "eat")
public class Demo03Annotation { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {// 1.获取当前类的Class对象Class<Demo03Annotation> c = Demo03Annotation.class;// 2.获取当前类的注解类的实例对象// 其实就是在内存中生成了一个注解接口的实现类对象/*其实编译器会自动生成如下的代码:public class ProImpl implements Pro {public String className() {return "priv/lwx/javaprac/annotation/Demo03Annotation";}public String methodName() {return "eat";}}*/Pro pro = c.getAnnotation(Pro.class);// 3.调用注解对象上的抽象方法,获取返回值String className = pro.className(); // 返回值就是使用Pro注解时所定义的className属性值String methodName = pro.methodName(); // 返回值就是使用Pro注解时所定义的methodName属性值System.out.println(className);System.out.println(methodName);// 使用Class的静态方法forName将类加载进内存中Class c2 = Class.forName(className);// 获取无参构造器Constructor constructor = c2.getConstructor();// 通过无参构造器创建对象Object obj = constructor.newInstance();// 获取方法对象Method method = c2.getMethod(methodName);// 执行方法Object result = method.invoke(obj);System.out.println(result);}}

总结

在实际开发过程中,多数情况我们不会自定义注解,而是使用注解。

注解给谁用?
给解析程序用,编译器也属于解析程序,解析程序识别注解,然后实现有关的业务逻辑。

注解可以理解为程序中一种标签、标记

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/332683.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle数据库硬恢复,Oracle数据库的可恢复性设置

整理自《Oracle 11g OCP/OCA 认证指南》001为了保证数据库的最大可恢复性&#xff0c;必须多路复用控制文件&#xff1b;必须多路复用联机重做日志&#xff1b;必须以归档日志模式运行数据库&#xff0c;并多路复用归档日志文件&#xff1b;最后必须作常规备份。002 保护控制文…

rest api如何创建_创建一个安全的Spring REST API

rest api如何创建“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕&#xff1f; 尝试使用Okta API进行托管身份验证&#xff0c;授权和多因素身份验证。 “如果有用&#xff0c;它将被修改。” 那些智慧的话来自我的QA老师…

IntelliJ IDEA 的 Build Project/Build Module/构建项目/构建模块/构建工程

文章目录Build ModuleRebuild ModuleBuild Module&#xff0c;构建模块。所谓“构建”&#xff0c;就是“构建”包及字节码文件&#xff0c;其实就是编译源码文件的动作了。所以 Build Module&#xff0c;就是把 src 目录的源代码文件以及 resources 下的资源文件&#xff0c;构…

oracle 修改nls_characterset,ORACLE NLS_CHARACTERSET字符集的更改

ORACLE NLS_CHARACTERSET字符集的更改      数据库创建以后&#xff0c;如果需要修改字符集&#xff0c;通常需要重建数据库&#xff0c;通过导入导出的方式来转换。      我们也可以通过以下方式更改      ALTER DATABASE CHARACTER SET      注意&#xff1a…

commons cli_从Commons CLI迁移到picocli

commons cli最初于2002年发布的Apache Commons CLI可能是使用最广泛的Java命令行解析器&#xff0c;但是它的API显示了它的年龄。 寻找具有最少样板代码的现代方法的应用可能对picocli感兴趣。 为什么要花麻烦的钱进行迁移&#xff0c;以及如何将基于Commons CLI的应用程序迁移…

乘方(幂)的运算法则/规则

文章目录乘方的定义运算法则正分数指数幂法则负分数指数幂法则同底数幂法则负整数指数幂法则乘方的定义 求相同因数的积叫做乘方。乘方运算的结果叫幂。 当 ana^nan 看作 a 的 n 次乘方的结果时&#xff0c;也可读作“a 的 n 次幂”或“ a 的 n 次方”。其中&#xff0c;a 叫…

php响应式布局,响应式布局之弹性布局的介绍

响应式布局的实现是前端工程中一个非常大的跨越&#xff0c;它非常灵活的可塑造性使得同一个网站能在不同的终端设备上展现出不同的活力。就今天这个机会&#xff0c;我想与大家分享并探讨一些常用来实现响应式布局方法中的弹性布局。弹性布局是一种十分方便的&#xff0c;只需…

qt弹簧教程_弹簧启动执行器教程

qt弹簧教程朋友您好&#xff0c;在本教程中&#xff0c;我们将学习弹簧执行器及其所有帮助。 1.什么是弹簧执行器&#xff1f; 2.如何在Maven项目或Gradle项目中添加弹簧执行器&#xff1f; 3.创建一个具有Spring Actuator依赖项的Spring Boot项目。 4.使用弹簧执行器端点监…

驾驶证遗失如何补发

第六十三条机动车驾驶证遗失的&#xff0c;机动车驾驶人应当向机动车驾驶证核发地或者核发地以外的车辆管理所申请补发。申请时应当填写申请表&#xff0c;并提交以下证明、凭证&#xff1a; &#xff08;一&#xff09;机动车驾驶人的身份证明&#xff1b; &#xff08;二&…

两列模糊对比 oracle,excel 模糊比对两列数据并将比对结果显示出来 | excel表格两列数据模糊对比...

excel2016如何将两列完全不一样的数据进行模糊对比&#xff1f;B2单元格输入公式IF(ISNUMBER(FIND(LEFT(A2,3),PHONETIC(G$2:G$8))),"","非类")下拉。 选中A、B列排可出非类似值。对G列的处理也是相同办法&#xff0c;修改一下公式中的单元格或区域引用即可…

JMetro版本5.2已发布

再次问好 JMetro的新更新刚刚发布。 添加了两种新的控件样式&#xff1a;标题窗格和手风琴。 此外&#xff0c;还对现有样式和错误修复进行了调整。 最终&#xff0c;JMetro现在也可以通过Maven Central获得。 在这篇文章中&#xff0c;我将详细介绍刚刚发布的JMetro 5.2版。…

IntelliJ IDEA for Mac 如何创建Java Web项目_创建Java EE项目_创建项目_新建项目

Java EE 项目创建好后如下图所示&#xff1a; 如果你的项目含有多个模块&#xff0c;那么上图的项目结构布局是不合理的&#xff0c;你必须将默认的模块删除掉&#xff08;默认模块的 .iml 文件也要删除&#xff09;。 选择模块&#xff0c;点按鼠标右键&#xff0c;选择【Rem…

注解代替枚举_精选枚举代替开关

注解代替枚举问题及其解决方案 开关/案例是用大多数命令式编程语言实现的通用控制结构。 开关比一系列的if / else更具可读性。 这是一个简单的示例&#xff1a; // Switch with int literal switch (c) {case 1: one(); break;case 2: two(); break;case 3: three(); break;…

oracle表是动态表怎么算排名,Oracle学习动态性能表

按照OracleDocument中的描述&#xff0c;v$sysstat存储自数据库实例运行那刻起就开始累计全实例(instance-wide)的资源使用情况。 类似于v$sOracle 学习动态性能表 v$locked_object本视图列出系统上的每个事务处理所获得的所有锁。V$LOCKED_OBJECT中的列说明&#xff1a;XIDUSN…

IntelliJ IDEA for Mac 中 Java Web Project 默认的工件(Artifacts)输出目录

你创建 Java Web 项目/模块时&#xff0c;IDEA 会自动创建 Web 模块的工件列表&#xff0c;而工件的默认输出目录如下&#xff1a; war 工件的默认输出目录&#xff1a; /Users/liaowenxiong/Documents/IdeaProjects/java-exercises/模块名称/target exploded 工件的默认输出…

oracle导数的数据乱码,Oracle10g导数据时中文乱码相关处理

1.Oracle导入数据库出现数据库数据中文乱码问题&#xff0c;最后查得是由于数据库安装时&#xff0c;选择编码为默认编码问题分析&#xff1a;使用imp导入数据时&#xff0c;屏幕输出过以下提提示信息&#xff1a;import done in US7ASCII character set and AL16UTF16 NCHAR c…

jdk12 jdk1.8_JDK 12的Files.mismatch方法

jdk12 jdk1.8JDK 12向Files类引入了一种新方法。 方法Files.mismatch(Path,Path)已通过JDK-8202302引入JDK 12&#xff0c;并在JDK 12 Early Access Build 20 &#xff08;支持新{systemProperty} Javadoc标记的相同早期访问版本&#xff09;中可用 。 JDK-8202302 [“用于比较…

tomcat如何查找请求资源的?

用户的请求过来&#xff0c;comcat 会根据虚拟目录先到 webapps 目录查找项目&#xff0c;如果找到了则进入到项目下的 WEB-INF 目录下查找 web.xml 文件&#xff0c;查找到则解析该文件&#xff0c;根据资源路径查找请求资源&#xff0c;如果找到了资源则正常实例化和调用有关…

java使用迭代器删除元素_使用Java从地图中删除元素

java使用迭代器删除元素关于从Java中的Map删除元素的非常简短的文章。 我们将专注于删除多个元素&#xff0c;而忽略了您可以使用Map.remove删除单个元素的Map.remove 。 以下Map将用于此帖子&#xff1a; Map<Integer, String> map new HashMap<>(); map.put(1…

IntelliJ IDEA普通的Java项目如何转成Maven Web项目

文章目录一、把项目改成 Java Web 项目二、把 Java Web 项目改成 Maven 项目三、调整目录结构四、部署项目五、参考一、把项目改成 Java Web 项目 注&#xff1a;只有 Web 项目才能创建 Artifact。 二、把 Java Web 项目改成 Maven 项目 得到的目录结构如下图所示&#xff1a;…