Java注释
Java注释(批注)用于为Java代码提供元数据。 Java注释是元数据,它并不直接影响代码的执行,尽管某些类型的注释实际上可以用于此目的。
Java注释已从Java 5添加到Java。此文本涵盖了Java注释在Java 8,Java 9及更高版本中的外观。据我所知,Java注释在更高的Java版本中没有更改,因此该文本也应适用于Java 8、9、10和11程序员。
Java注释目的
Java批注通常用于以下目的:
- 编译指令
- 建立时间指示
- 运行时说明
Java具有3个内置注释,可用于向Java编译器提供指令。这些注释将在本文后面详细说明。
在构建软件项目时,可以在构建时使用Java批注。构建过程包括生成源代码,编译源代码,生成XML文件(例如,部署描述符),将编译后的代码和文件打包到JAR文件中等。构建软件通常由自动构建工具(如Apache Ant或者Apache Maven)完成。 。生成工具可能会扫描Java代码中的特定注释,并根据这些注释生成源代码或者其他文件。
通过Java反射访问Java批注
通常,编译后Java注释不会出现在Java代码中。但是,可以定义自己的注释,这些注释在运行时可用。然后可以通过Java Reflection来访问这些批注,并用于为程序或者某些第三方API提供指令。我已经在我的Java Reflection and Annotations教程中介绍了如何通过反射访问Java注释。
基本注释
最短形式的Java注释如下所示:
@Entity
" @"字符向编译器表示这是一个注释。 @字符后的名称是注释的名称。在上面的示例中,注释名称为"实体"。
注释元素
Java批注可以包含我们可以为其设置值的元素。元素就像属性或者参数。这是带有元素的Java注释的示例:
@Entity(tableName = "vehicles")
此示例中的注释包含一个名为" tableName"的元素,其值设置为" vehicles"。元素被括在注释名称后的括号内。没有元素的注释不需要括号。
注释可以包含多个元素。这是一个多元素Java注释示例:
@Entity(tableName = "vehicles", primaryKey = "id")
如果注释仅包含单个元素,则习惯上将该元素命名为"值",如下所示:
@InsertNew(value = "yes")
当注释仅包含一个名为"值"的元素时,我们可以省略元素名称,而仅提供值。这是仅提供值的注释元素的示例:
@InsertNew("yes")
注释放置
我们可以在类,接口,方法,方法参数,字段和局部变量上方放置Java注释。这是在类定义上方添加的示例注释:
@Entity public class Vehicle { }
注释以" @"字符开头,后跟注释的名称。在这种情况下,注释名称为"实体"。实体注解是我制作的注解。在Java中没有任何意义。
这是一个更大的示例,在类,字段,方法,参数和局部变量上方都带有注释:
@Entity public class Vehicle { @Persistent protected String vehicleName = null; @Getter public String getVehicleName() { return this.vehicleName; } public void setVehicleName(@Optional vehicleName) { this.vehicleName = vehicleName; } public List addVehicleNameToList(List names) { @Optional List localNames = names; if(localNames == null) { localNames = new ArrayList(); } localNames.add(getVehicleName()); return localNames; } }
批注再次只是我制作的批注。它们在Java中没有特定的含义。
内置Java注释
Java带有三个内置注释,用于向Java编译器提供指令。这些注释是:
- @已弃用
- @Override
- @SuppressWarnings
以下各节将对这些注释中的每一个进行解释。
@Deprecated
@Deprecated批注用于将类,方法或者字段标记为已弃用,这意味着不应再使用它。如果代码使用了不赞成使用的类,方法或者字段,则编译器将向我们发出警告。这是@Deprecated Java注释示例:
@Deprecated public class MyComponent { }
在类声明上方使用Java批注@Deprecated将该类标记为已弃用。
我们还可以使用方法和字段声明上方的@Deprecated批注,将方法或者字段标记为已弃用。
当使用@ Deprecated
注释时,最好也使用相应的@ deprecated
JavaDoc符号,并说明为什么不赞成使用类,方法或者字段以及程序员应该使用什么。例如:
@Deprecated /** @deprecated Use MyNewComponent instead. */ public class MyComponent { }
@Override
上面的方法使用了@Override Java注释,这些方法将覆盖超类中的方法。如果该方法与超类中的方法不匹配,则编译器将给我们一个错误。
为了覆盖超类中的方法,不需要@Override注释。不过,仍然使用它是一个好主意。如果有人在超类中更改了覆盖方法的名称,则子类方法将不再覆盖它。没有@ Override
注释,我们将找不到答案。使用@Override批注,编译器会告诉我们子类中的方法不会覆盖超类中的任何方法。
这是一个@Override Java注释示例:
public class MySuperClass { public void doTheThing() { System.out.println("Do the thing"); } } public class MySubClass extends MySuperClass{ @Override public void doTheThing() { System.out.println("Do it differently"); } }
如果MySuperClass中的doTheThing()方法更改了签名,以使子类中的相同方法不再覆盖它,则编译器将生成错误。
@SuppressWarnings
@SuppressWarnings批注使编译器抑制给定方法的警告。例如,如果某个方法调用了不赞成使用的方法,或者进行了不安全的类型转换,则编译器可能会生成警告。我们可以通过使用@SuppressWarnings注释对包含代码的方法进行注释,从而消除这些警告。
这是一个@SuppressWarnings Java注释示例:
@SuppressWarnings public void methodWithWarning() { }
创建自己的Java注释
可以创建自己的(自定义)Java批注。注释在它们自己的文件中定义,就像Java类或者接口一样。顺便说一下,我已经创建了一个有关创建自己的Java批注的视频教程。我们可以在本段下面找到它。如果我们希望使用文字说明,只需向下滚动视频并继续阅读即可。
创建自己的Java注释视频教程
自定义Java注释示例
这是自定义Java注释示例:
@interface MyAnnotation { String value(); String name(); int age(); String[] newNames(); }
这个例子定义了一个名为" MyAnnotation"的注释,它包含四个元素。注意" @interface"关键字。这会向Java编译器发出信号,这是Java注释定义。
注意,每个元素的定义都类似于接口中的方法定义。它具有数据类型和名称。我们可以将所有原始数据类型用作元素数据类型。我们也可以使用数组作为数据类型。我们不能将复杂的对象用作数据类型。
要使用上面的注释,可以使用如下代码:
@MyAnnotation( value="123", name="Hyman", age=37, newNames={"Hyman", "Peterson"} ) public class MyClass { }
如我们所见,我必须为MyAnnotation批注的所有元素指定值。
元素默认值
我们可以为元素指定默认值。这样,该元素就成为可选元素,并且可以省略。这是一个注释定义的外观示例,该注释定义具有元素的默认值:
@interface MyAnnotation { String value() default ""; String name(); int age(); String[] newNames(); }
现在可以在使用注释时忽略"值"元素。如果我们将其保留,则将其视为我们已对value元素使用了默认值。这是一个注释的示例,其中元素值被忽略,因此该元素被设置为默认值:
@MyAnnotation( name="Hyman", age=37, newNames={"Hyman", "Peterson"} ) public class MyClass { }
注意,"值"元素不再存在。
@Retention
我们可以为自定义注释指定是否应在运行时可用,以通过反射进行检查。我们可以通过使用@Retention批注对批注定义进行批注来实现。这是完成的方式:
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation { String value() default ""; }
注意在MyAnnotation定义上方添加的@Retention注释:
@Retention(RetentionPolicy.RUNTIME)
这就是向Java编译器和JVM发出信号的提示,即注释应该在运行时通过反射可用。我的Java Reflection and Annotations教程中涵盖了在运行时访问注释,这是Java Reflection教程的一部分。
RetentionPolicy类包含两个可以使用的值:
RetentionPolicy.CLASS表示注释存储在.class文件中,但在运行时不可用。如果我们根本没有指定任何保留策略,则这是默认的保留策略。
RetentionPolicy.SOURCE表示注释仅在源代码中可用,而在.class文件和运行时中不可用。如果我们创建自己的注释以与扫描代码的构建工具一起使用,则可以使用此保留策略。这样,.class文件就不会受到不必要的污染。
@Target
我们可以指定自定义注释可用于注释哪些Java元素。为此,可以使用@Target批注对批注定义进行批注。这是一个@Target Java注释示例:
import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target({ElementType.METHOD}) public @interface MyAnnotation { String value(); }
此示例显示了Java注释,该注释只能用于对方法进行注释。
ElementType类包含以下可能的目标:
- ElementType.ANNOTATION_TYPE
- ElementType.CONSTRUCTOR
- ElementType.FIELD
- ElementType.LOCAL_VARIABLE
- ElementType.METHOD
- ElementType.PACKAGE
- ElementType.PARAMETER
- ElementType.TYPE
其中大多数是自我解释,但有一些不是。因此,我将说明目标不明确的目标。
" ANNOTATION_TYPE"目标表示Java注释定义。因此,注释只能用于注释其他注释。就像@Target和@Retention注释一样。
" TYPE"目标表示任何类型。类型可以是类,接口,枚举或者注释。
@Inherited
" @Inherited"注释表示从该类继承的子类应继承该类中使用的自定义Java注释。这是一个@Inherited Java注释示例:
java.lang.annotation.Inherited @Inherited public @interface MyAnnotation { }
@MyAnnotation public class MySuperClass { ... }
public class MySubClass extends MySuperClass { ... }
在这个例子中,类MySubClass继承了注解@MyAnnotation,因为MySubClass继承了MySuperClass,而MySuperClass具有@MyAnnotation注释。
@Documented
@Documented注解用于向JavaDoc工具发出信号,表明使用自定义注释的类的自定义注释应在JavaDoc中可见。这是一个@Documented Java注释示例:
import java.lang.annotation.Documented; @Documented public @interface MyAnnotation { }
@MyAnnotation public class MySuperClass { ... }
在为MySuperClass类生成JavaDoc时,JavaDoc中现在包含了@MyAnnotation。
我们不会经常使用@ Documented
注释,但是现在我们知道它是否存在,如果需要的话。