从零开始学Java之你会用注解吗?

作者 :孙玉昌,昵称【一一哥 】,另外【壹壹哥】也是我哦

千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者

前言

在上一篇文章中,壹哥 给大家介绍了"枚举"的内容,相信大家都已经掌握了这个简单知识的用法。今天我会给大家再介绍另一个简单的小知识,这就是"注解"!可能有些小伙伴听到这个名字会一愣,"注解"还要学习吗?我们之前在刚开始学Java时不是已经学习过了吗?壹哥请各位再仔细看一下,今天我们要学习的是"注解",不是"注释"哦!那么"注解"有什么特点呢?让我们一起来看看吧。

------------------------------前戏已做完,精彩即开始----------------------------

全文大约【4300】 字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考......

配套开源项目资料

Github: github.com/SunLtd/Lear...

Gitee: gitee.com/sunyiyi/Lea...

一. 注解简介

1. 概念

注解是Java 5中推出的一种修饰符。从本质上来说,注解是一种元数据,可以为程序的各种元素(如类、方法、变量和参数)提供额外的补充信息。这些信息可以在编译、部署和运行时使用,但不会直接影响程序的执行。

这里壹哥给大家提到了"元数据"的概念,所谓的"元数据",是指可以提供与程序相关信息的数据。其中,"元"是"开头、第一、起始、最初、本源"的意思。所以,我们可以把"元数据"简单地理解为"初始的数据"。

从功能上来看,注解可以帮助我们实现很多效果,比如在项目编译时进行辅助检查、指示编译器生成代码,或者指示各种框架生成代码等。

另外,注解还和后面要学习的反射有着紧密的关系。我们可以利用反射来获取注解上携带的元数据等信息,比如可以使用反射来得到某个方法上的注解值,进而对这个方法进行一些高级的操作。关于反射,壹哥会在下一篇文章中给大家讲解,欢迎期待哦。

2. 注解与注释的区别

有些初学者因为知识掌握的不扎实,会把"注解"和"注释"搞混,其实这是两个完全不同的技术,差别很大。注解和注释虽然都是在代码中提供信息的方式,但它们的目的和使用方式有很大不同,其区别主要有以下几点:

  • 注释是对相关代码进行解释说明,而注解是给有关代码提供额外的信息;
  • 注释是帮助开发人员理解代码的,它们不会影响程序的执行。而注解常用于在代码中提供元数据,它们可以在编译、部署和运行时使用,也不会直接影响程序的执行;
  • 注释可以用于任何的程序元素,而注解通常用于类、方法、变量和参数等声明上。

3. 使用场景

那么注解到底可以在哪些地方使用呢?比较常见的场景包括但不限于以下几个:

  1. 编译时检查:编译器可以检查某个注解是否存在,以及它们是否适用于特定的上下文。
  2. 指示编译器生成代码:注解可以指示编译器生成额外的代码。例如,使用注解可以指示编译器是否生成hashCode和equals方法。
  3. 指示框架生成代码:注解可以指示框架生成额外的代码。例如,使用注解可以指示Spring框架生成各种bean。
  4. 运行时处理:注解可以在运行时进行代码处理,例如使用反射来查找注解以实现某些特定的功能。

尤其是在各种框架中,更是大量使用了注解,比如Spring、Hibernate、JUnit、Jersey、Spring Boot和Spring Cloud等。

其中,Spring框架使用了大量的注解来实现依赖注入、AOP等功能;Hibernate框架使用了大量注解来实现数据访问;JUnit框架使用注解来标记测试方法和测试类;Jersey框架会使用注解来标记资源和方法。

而在Spring Boot和Spring Cloud中,也给我们提供了大量的注解来简化开发,并提供更多的功能。比如Spring Boot中有 @SpringBootApplication、@RestController, Spring Cloud中有 @EnableDiscoveryClient、@EnableCircuitBreaker、@FeignClient等 注解

总之,这些注解简化了程序的开发,并给我们提供了许多工具和功能来构建出高质量的代码,大大提高了我们的开发效率。

4. 注解类型

在Java中存在大量的注解,整体上可以分为以下三种类型:

  • 元注解 :用于注解其他的注解,即"注解的注解"。Java 5中给我们定义了四个元注解: @Retention、@Target、@Documented和@Inherited
  • 内置注解:Java 5中有五个内置注解,后来在Java 8中又引入了两个,这7个内置注解包括:@Override、@Deprecated、@SuppressWarnings、@FunctionalInterface、@SafeVarargs、@Repeatable、@Native。
  • 自定义注解:如果你觉得以上这些注解不够用,我们就可以自定义注解了,用于特定的用途。实际上各种开源框架中的注解,都属于自定义注解。

二. 基本使用

1. 基本语法

注解的使用很简单,我们在使用时以 "@" 符号开头 ,后面跟着注解的名称即可。当然每个注解都有自己的作用范围,不能到处乱用。另外我们在使用注解时,要注意注解中可以带有元素,这些元素可以在声明注解时设置初始值。使用注解的基本语法如下:

java 复制代码
@AnnotationName(elementName = elementValue)
public void methodName() {
    // method body
}

为了让大家更好地理解注解的用法,接下来壹哥就通过几个案例,来给大家讲解内置注解的用法。

2. 基本案例

2.1 内置注解含义

我们知道,Java 5中给我们引入了五个内置注解,后来在Java 8中又引入了两个,这7个内置注解的作用如下:

  • @Override:用于指明某个方法重写了父类中的方法。
  • @Deprecated:用于指明某个方法或类已过时,不再建议使用。
  • @SuppressWarnings:用于抑制编译器警告,可以在类、方法、变量和参数等声明上使用。
  • @FunctionalInterface:用于指明某个接口是函数式接口。函数式接口是指只包含一个抽象方法的接口。
  • @SafeVarargs:用于指明某个方法使用了安全变长参数。它可以应用在静态方法、实例方法、构造函数和类上。
  • @Repeatable:用于指明某个注解可以在同一个代码元素上重复使用,它可以用在注解上。
  • @Native:用于指明某个方法的实现是本地方法。本地方法是指用其他语言(比如C、C++)编写的方法,它们可以使用Java Native Interface(JNI)与Java代码进行通信。

2.2 使用方式

第一个案例是关于@Override注解的用法,代码如下:

java 复制代码
//父类
public class Parent {
    //父类中的同名方法
    public void print() {
        System.out.println("Parent");
    }
}

//子类
public class Child extends Parent {
    //子类中的同名方法,重写了父类的同名方法
    @Override
    public void print() {
        System.out.println("Child");
    }
}

在这个例子中,我们在Child类的print()方法上使用了@Override注解,该注解就表明了子类的print()方法是覆盖了父类的同名方法。如果我们不小心写错了print()的方法名,编译器就会报错,这是因为我们使用了@Override注解来表明该方法是被覆盖的。所以,@Override注解主要是帮助我们避免因为错误的方法覆盖而引起的问题。

接下来第二个案例是使用@Deprecated注解的例子,代码如下:

java 复制代码
@Deprecated
public void oldMethod() {
    // method body
}

在这个例子中,oldMethod()方法被@Deprecated注解标记为过时的。如果我们在代码中调用了这个方法,编译器就会发出过时的警告,方法上会有黑色横线提升。

最后我们再来看看@SuppressWarnings注解的例子,代码如下:

java 复制代码
@SuppressWarnings("unchecked")
public List<String> getList() {
    return new ArrayList();
}

在这个例子中,getList()方法会被标记为"抑制未经检查的警告"。如果我们没有使用@SuppressWarnings注解,编译器会发出黄色叹号的警告,因为这里的getList()方法返回的是一个未经检查的List类型。

其他的内置注解用法与这些大同小异,只是各自都有不同的使用时机。总之,这些内置注解可以帮助我们编写出更加清晰、易于维护的代码,并提高代码的可读性和可靠性,请大家牢牢记住这几个内置注解即可。

如果你觉得这些内置注解不够用,那我们也可以自定义注解,以实现更多功能。

三. 自定义注解

1. 基本语法

如果我们想根据项目的特殊需要进行自定义注解,此时可以使用@interface关键字进行声明,并且要指定元注解、注解的类型和注解的生命周期。一般情况下,自定义注解的语法如下所示:

java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
    String value();
}

在这个示例中,壹哥 给大家自定义了一个新的注解@CustomAnnotation。在自定义这个注解时,壹哥用到了另外的4个元注解,分别是@Target和@Retention。那么这2个元注解具体有哪些含义呢?我们往下看。

2. 核心元注解

2.1 @Retention

@Retention是Java的一个元注解,用于指定注解的保留策略,或者说是注解的生命周期。Java 5中给我们定义了三种保留策略:

  • RetentionPolicy.SOURCE:表示该注解仅保留在源代码中,编译器会在编译阶段忽略掉它们,生命周期最短。
  • RetentionPolicy.CLASS:表示该注解会被编译器保留在类文件中,但在运行时不可用,生命周期居中。
  • RetentionPolicy.RUNTIME:表示该注解会被编译器保留在类文件中,并在运行时也可以使用,生命周期最长。

我们这里所谓的"保留策略",也可以说成是"生命周期",也就是某个注解可以存活生效的阶段。比如,如果我们想在运行时也能使用自定义的注解,就可以使用以下声明:

java 复制代码
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    // annotation elements
}

在这个例子中,@MyAnnotation这个自定义的注解被指定为RetentionPolicy.RUNTIME保留策略,所以它在运行时也可以使用。

另外,RetentionPolicy是一个枚举类,里面带了SOURCE、CLASS和RUNTIME这3个值,如下图所示:

2.2 @Target

@Target也是一个元注解,主要用于指定注解的作用范围,比如类、方法、变量和参数等。Java 5中给我们定义了以下几种作用范围:

  • ElementType.ANNOTATION_TYPE:表示该注解适用在注解类型上。
  • ElementType.CONSTRUCTOR:表示该注解适用于构造函数上。
  • ElementType.FIELD:表示该注解适用于域或属性上。
  • ElementType.LOCAL_VARIABLE:表示该注解适用于局部变量。
  • ElementType.METHOD:表示该注解适用于方法。
  • ElementType.PACKAGE:表示该注解适用于包。
  • ElementType.PARAMETER:表示该注解适用于方法参数。
  • ElementType.TYPE:表示该注解适用于类、接口和枚举类型。

其中ElementType也是一个枚举类,主要是配合@Target注解。

使用@Target元注解并配合ElementType,我们就可以限制某个注解的适用范围,从而确保注解的正确使用。

了解完这些理论内容之后,接下来我们再来看看具体的开发步骤吧。

3. 实现步骤

要想自定义一个注解,我们可以遵循以下实现步骤:

  1. 首先使用@interface关键字声明一个注解;
  2. 在该注解上指定元注解(@Retention、@Target);
  3. 然后指定注解的类型(如ElementType.METHOD);
  4. 接着自定义元素,表明该注解的基本属性;
  5. 最后在需要使用注解的地方,正确使用自定义的注解。

接下来壹哥就按照以上实现步骤,来给大家演示具体的自定义注解实现过程。

4. 实现案例

在以下代码中,壹哥定义了一个自定义注解@CustomAnnotation,该注解可以应用于方法,并具有一个String类型的元素value,代码如下:

java 复制代码
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author 一一哥Sun
 * @company 千锋教育
 */
@Target(ElementType.METHOD)//限定作用范围
@Retention(RetentionPolicy.RUNTIME)//限定生命周期
public @interface CustomAnnotation {
    //自定义元素
    String value();
}

我们把这个注解可以在需要的方法上使用,如下所示:

java 复制代码
/**
 * @author 一一哥Sun
 * @company 千锋教育
 */
public class Demo01 {
    //@CustomAnnotation
    //private String name;//不能在方法之外的其他地方使用这个自定义的注解,否则会报错

    //使用自定义的注解
    @CustomAnnotation(value = "一一哥")
    public void myMethod() {
        // method body
    }
}

在这个例子中,myMethod()方法被可以@CustomAnnotation注解修饰,并且在该注解中带有一个元素value值"一一哥"。以后我们可以通过反射等技术,获取该注解的元素值,进而就可以进行其他的操作了。

5. 注意事项

注解的使用虽然简单,但我们在使用注解时,也需要注意以下几点:

  • 注解主要是用于提供元数据,而不要直接影响程序的运行。因此,我们不能滥用注解,以免影响程序的可读性和维护性。
  • 注解的定义应该清晰、简洁、易于理解,在注解的文档中要提供有关该注解的详细信息。
  • 不同的注解要对应不同的保留策略和作用范围,应该根据需要选择合适的注解。
  • 注解可以用于编译时检查、指示编译器生成代码、指示框架生成代码等,但注意不要过度依赖注解,以免影响程序的性能。

------------------------------正片已结束,来根事后烟----------------------------

四. 结语

通过今天的文章,壹哥就给大家介绍了Java里的注解。现在我们知道,注解是Java 5中推出的一项新功能,它们是一种元数据,可以为程序元素提供额外的信息,但并不会直接影响程序的执行。Java的注解有三种类型:元注解、内置注解和自定义注解。在开发时,我们可以根据需要自定义注解,并使用它们来提供有关代码的额外信息。

总之,注解是一种非常有用的元数据,可以给我们提供有关代码的额外信息,但要合理使用,以免影响程序的可读性和维护性,过度依赖注解也可能会导致程序的性能下降。

另外如果你独自学习觉得有很多困难,可以加入壹哥的学习互助群,大家一起交流学习。

相关推荐
Ylucius33 分钟前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
凡人的AI工具箱44 分钟前
AI教你学Python 第11天 : 局部变量与全局变量
开发语言·人工智能·后端·python
是店小二呀1 小时前
【C++】C++ STL探索:Priority Queue与仿函数的深入解析
开发语言·c++·后端
七夜zippoe1 小时前
分布式系统实战经验
java·分布式
canonical_entropy1 小时前
金蝶云苍穹的Extension与Nop平台的Delta的区别
后端·低代码·架构
是梦终空1 小时前
JAVA毕业设计176—基于Java+Springboot+vue3的交通旅游订票管理系统(源代码+数据库)
java·spring boot·vue·毕业设计·课程设计·源代码·交通订票
落落落sss1 小时前
sharding-jdbc分库分表
android·java·开发语言·数据库·servlet·oracle
码爸1 小时前
flink doris批量sink
java·前端·flink
我叫啥都行2 小时前
计算机基础知识复习9.7
运维·服务器·网络·笔记·后端
Monodye2 小时前
【Java】网络编程:TCP_IP协议详解(IP协议数据报文及如何解决IPv4不够的状况)
java·网络·数据结构·算法·系统架构