【Java高级语法】(十三)注解:解码程序设计中的元数据利器,在小小的@符里挖呀挖呀挖~用小小的注解做强大的开发...

Java高级语法详解之注解

  • 1️⃣ 概念
  • 2️⃣ 优势和缺点
  • 3️⃣ 使用
    • 3.1 元注解
    • 3.2 自定义注解
    • 3.3 常用内置注解
  • 4️⃣ 应用场景
  • 5️⃣ 底层原理
  • 6️⃣ 扩展:那些流行框架中的注解
  • 🌾 总结

在这里插入图片描述

1️⃣ 概念

Java 注解(Annotation) 是Java语言中一种元数据形式,它提供了一种在代码中添加元数据的方式。注解为程序员提供了向代码中添加额外信息的能力,这些额外信息可以被编译器、工具或者运行时环境使用。

2️⃣ 优势和缺点

优点:

  • 提供了一种更加简洁和可读性强 的代码编写风格;
  • 增强代码的可维护性和可重用性,通过使用注解可以减少重复的代码;
  • 可以帮助开发者在编译时检测错误,提高代码的健壮性。

缺点:

  • 过度使用注解会使代码变得复杂和难以理解;
  • 注解的滥用可能导致代码过于依赖于特定的框架或工具,降低了代码的可移植性;
  • 注解可能增加代码的复杂性,并且可能需要花费更多的时间来学习和理解其使用方式。

3️⃣ 使用

3.1 元注解

元注解也是一种注解,用于对其他注解进行注释。Java提供了几种元注解,用于自定义和修饰注解声明,包括以下几种:

  • @Retention:指定注解的生命周期,可选值包括SOURCECLASSRUNTIME
  • @Target:指定注解可以应用的目标元素类型,如类、方法、字段等;
  • @Documented:指定注解是否包含在API文档中;
  • @Inherited:指定子类是否继承父类的注解;
  • @Repeatable:指定该注解可以被多次应用于同一元素。

3.2 自定义注解

在Java中,我们可以自定义注解,以满足特定的需求。自定义注解使用@interface关键字进行声明。

下面是一个使用上文元注解的简单演示案例程序,展示了如何在Java中应用这些注解来自定义一个注解:

import java.lang.annotation.*;// 定义一个自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
@Repeatable(MyAnnotations.class)
@interface MyAnnotation {String value() default "";
}// 定义一个可重复注解容器
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface MyAnnotations {MyAnnotation[] value();
}// 使用自定义注解
@MyAnnotation("Class Annotation")
public class DemoClass {@MyAnnotation("Field Annotation")private String field;@MyAnnotation("Constructor Annotation")public DemoClass() {// 构造函数注解}@MyAnnotation("Method Annotation")public void demoMethod() {// 方法注解}public static void main(String[] args) {DemoClass obj = new DemoClass();Class<? extends DemoClass> clz = obj.getClass();// 获取类上的注解MyAnnotation classAnnotation = clz.getAnnotation(MyAnnotation.class);System.out.println("Class Annotation: " + classAnnotation.value());// 获取字段上的注解try {java.lang.reflect.Field field = clz.getDeclaredField("field");MyAnnotation fieldAnnotation = field.getAnnotation(MyAnnotation.class);System.out.println("Field Annotation: " + fieldAnnotation.value());} catch (NoSuchFieldException e) {e.printStackTrace();}// 获取构造函数上的注解try {java.lang.reflect.Constructor<?> constructor = clz.getDeclaredConstructor();MyAnnotation constructorAnnotation = constructor.getAnnotation(MyAnnotation.class);System.out.println("Constructor Annotation: " + constructorAnnotation.value());} catch (NoSuchMethodException e) {e.printStackTrace();}// 获取方法上的注解try {java.lang.reflect.Method method = clz.getDeclaredMethod("demoMethod");MyAnnotation methodAnnotation = method.getAnnotation(MyAnnotation.class);System.out.println("Method Annotation: " + methodAnnotation.value());} catch (NoSuchMethodException e) {e.printStackTrace();}}
}

这段代码演示了如何定义和使用自定义注解,并从类、字段、构造函数和方法中获取注解的值。

首先,我定义了一个自定义注解 @MyAnnotation。注解的定义可以通过多个元注解修饰,这些元注解用于为注解提供额外的信息:

  • @Retention(RetentionPolicy.RUNTIME):指定注解保留的生命周期为运行时。这意味着注解将在运行时仍然可见,可以通过 Java 反射机制获取;
  • @Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.CONSTRUCTOR}):指定注解可以应用于类、字段、方法和构造函数上;
  • @Documented:指定该注解将包含在 Javadoc 中;
  • @Inherited:指定子类默认继承父类的注解。

之后,在 DemoClass 类上、类中的字段、构造函数和方法上都使用了自定义注解 @MyAnnotation

main 方法中,首先创建了一个 DemoClass 对象 obj,通过反射获取 DemoClass 类的实例对象的运行时类型以及类上的注解。

接着,通过反射机制分别获取字段上的注解、构造函数上的注解、方法上的注解。并且打印了相应注解的值,以演示如何从类、字段、构造函数和方法中获取注解的值。

通过自定义注解,我们可以根据需要添加元数据,并在代码中使用它。

3.3 常用内置注解

Java提供了很多内置的注解,我们来介绍几个常用的注解:

  • @Override:用于标记方法覆写(重写)父类的方法,可以帮助我们检查是否正确地覆写了方法;
  • @Deprecated:用于标记过时的方法或类,在程序中使用过时的元素会收到警告提示,鼓励使用更合适的替代方案;
  • @SuppressWarnings:用于抑制编译器产生的警告信息,可以让代码看起来更整洁,但需谨慎使用;
  • @FunctionalInterface:用于标记函数式接口(只有一个抽象方法),可以确保接口的语义符合函数式编程的要求。

下面是一个使用Java实现的演示案例程序,展示了如何使用@Override@Deprecated@SuppressWarnings@FunctionalInterface注解:

import java.util.ArrayList;
import java.util.List;class Parent {public void display() {System.out.println("Parent class");}
}class Child extends Parent {@Overridepublic void display() {System.out.println("Child class");}
}@Deprecated
class DeprecatedClass {@Deprecatedpublic void deprecatedMethod() {System.out.println("\nThis method is deprecated.");}
}@SuppressWarnings("unused")
class SuppressWarningsClass {// unused fieldprivate int unusedVariable;@SuppressWarnings("unchecked")public void suppressWarningsMethod() {List list = new ArrayList();list.add("item");System.out.println("\n" + list);}
}@FunctionalInterface
interface FunctionalInterfaceExample {void someMethod();
}public class AnnotationDemo {public static void main(String[] args) {// @Override exampleParent parent = new Parent();Child child = new Child();parent.display();           // Output: Parent classchild.display();            // Output: Child class// @Deprecated exampleDeprecatedClass  deprecatedObject = new DeprecatedClass();deprecatedObject.deprecatedMethod();  // Output: This method is deprecated.// @SuppressWarnings exampleSuppressWarningsClass suppressWarningsObject = new SuppressWarningsClass();suppressWarningsObject.suppressWarningsMethod();  // No warning will be generated// @FunctionalInterface exampleFunctionalInterfaceExample functionalInterfaceObject = () -> System.out.println("\nFunctional Interface");functionalInterfaceObject.someMethod();  // Output: Functional Interface}
}

在这个示例程序中,我们创建了Parent类和Child类,其中Child类使用@Override注解来标记覆写(重写)了Parent类中的display()方法。这样在编译时,如果有错误地覆写了父类的方法,编译器将会给出错误提示。

另外,我们还创建了一个名为DeprecatedClass的过时类,并在其中的方法和类声明上都使用了@Deprecated注解。当我们在程序中使用过时的方法或类时,编译器会发出警告,鼓励我们使用更合适的替代方案。

同样,我们还创建了一个名为SuppressWarningsClass的类,在该类的方法和字段上使用了@SuppressWarnings注解来抑制编译器产生的警告信息,以便让代码看起来更整洁。但是需要注意,谨慎使用此注解,确保其使用场景合理。

再者,我们创建了一个函数式接口FunctionalInterfaceExample,并使用@FunctionalInterface注解进行标记。这个注解可以确保该接口只有一个抽象方法,从而符合函数式编程的要求。

最后,在main方法中展示了如何使用这些注解的例子,运行程序验证结果如下:

Parent class
Child classThis method is deprecated.[item]Functional Interface

4️⃣ 应用场景

Java注解广泛应用于各个领域,包括但不限于以下几个方面:

  • 标记/标识:注解可以用于对类、方法、字段等进行标记,以便将来在编译期、运行时或工具处理期间根据标记进行特定操作;
  • 配置/设置:注解可以用于配置代码,在运行时根据注解的参数动态地控制程序的行为;
  • 生成代码/文档:通过使用注解,可以自动生成代码、配置文件或文档等。

5️⃣ 底层原理

Java注解的底层原理主要涉及两个关键部分:反射(Reflection)和代理模式(Proxy)。下面逐步介绍这两个概念,以及它们与Java注解的关系。

  1. 反射(Reflection):
    反射是Java语言的一种特性,允许程序在运行时检查和修改自身的行为。通过反射,我们可以动态获取类的信息、调用方法和访问字段等。所以在使用注解时,需要使用反射来解析注解并执行相应的操作。

  2. 代理模式(Proxy):
    代理模式允许一个对象(代理对象)控制另一个对象(目标对象)的访问。在使用注解时,通常会有一个注解处理器(Annotation Processor)作为代理对象,负责在编译期或运行时扫描代码中的注解,并进行相应的处理。

Java注解的底层原理如下:

  • 在编译期:当我们在源代码中添加注解时,编译器会首先读取并解析这些注解。然后,在编译过程中,注解处理器会根据注解的类型执行相应的逻辑,并生成一些额外的代码。
  • 在运行时:当编译完成后,生成的字节码文件中会包含注解的信息。在运行时,Java虚拟机(JVM)通过反射读取这些已编译的注解,并执行相应的操作。注解处理器也可以在运行时扫描类路径上的字节码文件,获取注解信息并进行进一步的处理。

总结来说,Java注解的底层原理主要利用了反射和代理模式。反射机制使得我们能够动态读取和修改注解信息,而代理模式则通过注解处理器来实现对注解的解析和处理。这种机制为开发人员提供了一种方便且灵活地处理元数据的方式,并且在许多框架和工具中得到了广泛的应用。

6️⃣ 扩展:那些流行框架中的注解

在各个流行框架中,注解都起着重要的作用。它们为开发者提供了一种简洁、灵活和快速的方式来配置和扩展应用程序。

下面列举了一些主要流行框架中注解的应用范例:

  1. Spring

    • @Component:标记类为一个可被Spring容器管理的组件;
    • @Controller:标记控制器类,用于处理用户请求;
    • @RequestMapping:在控制器方法上定义路由规则与请求的映射关系;
    • @Service:标记服务层类,在业务逻辑中使用;
    • @Repository:标记数据访问层类,使得 Spring 可以自动将其纳入到 bean 容器;
    • @Autowired:自动将依赖注入到相应的类中,简化了组件间的耦合关系;
    • @Configuration:标记类为Spring配置类;
    • @Bean:标记方法返回值为Spring Bean,并由容器管理。
  2. Spring Boot

    • @SpringBootApplication:标记引导类,表示一个 Spring Boot 应用程序入口点;
    • @RestController:结合了 @Controller@ResponseBody,用于构建 RESTful API 控制器;
    • @RequestMapping:指定请求的 URL 路径和 HTTP 方法与方法的映射关系;
    • @ConfigurationProperties:绑定属性文件或环境变量到 Java Bean,方便地进行配置管理;
    • @EnableAutoConfiguration:启用自动配置,根据类路径下的依赖和规则推断、添加 Bean。
  3. Spring Cloud

    • @EnableDiscoveryClient:启用服务发现;
    • @EnableCircuitBreaker:启用断路器;
    • @FeignClient:声明一个可调用远程服务的客户端接口;
    • @EnableZuulProxy:启用Zuul代理网关;
    • @LoadBalanced:启用负载均衡客户端。
  4. Spring MVC

    • @Controller:标记类为MVC控制器;
    • @RequestMapping:将请求映射到控制器的方法上;
    • @RequestParam:将请求参数映射到方法参数上;
    • @PathVariable:将URL路径变量映射到方法参数上;
    • @ResponseBody:将方法返回值序列化成响应主体。
  5. MyBatis

    • @Mapper:标记接口为MyBatis的映射器;
    • @Select:定义查询语句;
    • @Insert:定义插入语句;
    • @Update:定义更新语句;
    • @Delete:定义删除语句;
    • @Param:指定方法参数与SQL语句中的参数对应关系等。
  6. Hibernate

    • @Entity:声明实体类;
    • @Table:指定实体类与数据库表之间的映射关系;
    • @Column:定义属性与数据库列之间的映射关系;
    • @Id:标识实体类的主键属性;
    • @GeneratedValue:指定主键生成策略;
    • @ManyToOne:定义多对一关系。
  7. Junit

    • @Test:标记测试方法;
    • @Before:在每个测试方法执行前被执行的方法;
    • @After:在每个测试方法执行后被执行的方法;
    • @RunWith:指定测试运行器,如使用 Spring 进行测试时可以指定 @RunWith(SpringRunner.class)
    • @BeforeEach:在每个测试方法之前运行的方法(JUnit 5);
    • @AfterEach:在每个测试方法之后运行的方法(JUnit 5);
    • @ParameterizedTest:参数化测试方法(JUnit 5)。

注解在这些框架中广泛应用,通过提供特定的注解,开发者可以方便地实现配置、路由、依赖注入、持久化等相关功能,大大简化了开发过程。同时,注解也为框架提供了更好的扩展性和灵活性。

🌾 总结

Java注解提供了一种简洁、灵活和强大的方式来为代码添加额外的元数据信息。它们能够提高代码的可读性、可维护性和健壮性。尽管有一些缺点,但合理地使用注解将带来很多好处。随着时间的推移,注解已经成为许多流行框架和库的核心组成部分。


在这里插入图片描述

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

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

相关文章

【Java】顺序表ArrayList

文章目录 一、顺序表二、ArrayList 的简介三、ArrayList 的使用3.1 构造方法3.2 常见操作3.3 遍历方法3.4 扩容机制 四、ArrayList 的模拟实现五、ArrayList 的使用案例5.1 扑克牌案例5.2 杨辉三角案例 六、ArrayList 存在的问题 一、顺序表 顺序表&#xff08;Sequential Lis…

js vuejs dagre-d3绘制流程图实用指南 有向图可视化

写在前面 之前有小伙伴问我如何使用 D3 在前端绘制流程图,今天在这里给安排上,与大家分享。 明确一点,只要你的数据计算能力足够强,使用原生D3绘制流程图绝对可以的,但是,为了让大家更容易上手,避免重复造轮子,给大家推荐一个专门绘制流程图的 D3 插件 dagre-d3。 首…

基于Flask+Bootstrap+机器学习的世界杯比赛预测系统

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Springboot分布式事务

一、先了解什么是本地事务 1. 概念 本地事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器位于同一节点相同数据库上。 又称为传统事务。它是一个操作序列&#xff0c;这些操作要么都执行&#xff0c;要么都不执行&#xff0c;是一个不可分割的工作单位。例…

你真的不想知道怎么用ai绘画图片生成图片吗?

亲爱的二次元迷们&#xff0c;你是否曾经梦想过能够画出自己心中的二次元角色&#xff0c;让他们跃然纸上、生动活泼地展现在世人面前&#xff1f;但是&#xff0c;面对空白的画板和一支笔&#xff0c;我们有时会感到无从下手&#xff0c;毫无艺术细胞可言。不要失望&#xff0…

贵阳阿里云代理商:阿里云中国区副总裁李国欢:数字经济与实体经济如何融合

中国青年报客户端讯&#xff08;中青在线记者 于璧嘉&#xff09;6月21日&#xff0c;在第六届世界智能大会即将召开之际&#xff0c;阿里云中国区副总裁李国欢在接受媒体专访时表示&#xff1a;“数字经济已经成为社会生产力革命的一个重要生产要素。” 6月21日&#xff0c;阿…

如何批量将PDF转换为图片?

在生活工作中&#xff0c;我们会处理很多电子合同。这些电子合同一般是PDF格式&#xff0c;不但存储空间大&#xff0c;且预览起来不太便捷&#xff0c;需要我们转换为图片格式更方便预览。如果人工一一处理比较繁琐复杂&#xff0c;有没有什么方案可以快速将pdf转换为图片呢&a…

[STC32F12K54入门第三步]USART1+Modbus RTU从机

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、Modbus RTU是什么?二、Modbus RTU程序展示1.串口配置2.Timer定时器配置3.配置CRC16校验位和Modbus RTU发送函数4.主函数5.效果展示总结提示:以下是本篇文章正文内容,下面案例可供参考 一、…

基于Java连锁经营商业管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

Linux之Kafka保姆式详细安装教程

下载Kafka 《Kafka官网下载》 注意&#xff1a;下载的是二进制文件&#xff0c;不要下载源码&#xff01;这里可以采用第三方下载工具加速下载&#xff0c;如&#xff1a;迅雷等 上传到Linux服务器的/data/目录下进行解压 tar -zxvf是解压文件命令&#xff0c;-C表示把解压…

Airtest:Windows桌面应用自动化测试四【Airtest之python本地环境安装、独立IDE运行】

Airtest之python本地环境安装、独立IDE运行 一、环境配置二、安装Airtest三、安装poco四、常见问题4.1若运行代码时&#xff0c;在cv2模块报ImportError: DLL load failed: 找不到指定模块的错&#xff0c;有几种解决方案&#xff1a;4.1.1.本问题的根本原因应该是DLL文件的缺失…

Elasticsearch:install

ElasticSearch Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。 Elasticsearch结合Kibana、Logstash、Beats&#xff0c;也就是elastic stack(ELK)。被广泛应用在日志分析、实时监控&#xff08;CPU、Memory、Program&#xff09;等领域。 elasticsearch是…