批处理注释bat注释一行
在Java中,大多数情况下,批注和批注处理器都被一团谜团包围。 他们似乎是为“专家”保留的主题。最重要的是,我认为他们周围还存在一些FUD 。该职位旨在以尽可能中立的方式深入探讨该主题。这样,每个人都可以做出明智的决定基于事实,而不是聆听充满误解或隐藏议程的人们。
自Java版本5(代号为Tiger)于2004年发布以来,便可以使用注释。
在Java计算机编程语言中,注释是一种语法元数据,可以添加到Java源代码中。 类,方法,变量,参数和Java包可能会带有注释。
https://zh.wikipedia.org/wiki/Java_annotation
最简单的注释如下所示:
@MyAnnotationpublicclassFoo{}
由于缺少注释,以前的Java版本必须以倾斜的方式使用某些功能。
-
更换
-
自Java诞生以来,就需要标记一个类或类的层次结构。 在Java 5之前,这是通过没有方法的接口完成的。
Serializable
和可Cloneable
是此类接口的两个示例。这种接口显然不同于其他接口:它们在自己和实现类之间未定义任何协定。 因此,他们赢得了标记器接口的名称。
Java新手通常会问与该方法有关的问题。 这样做的原因是因为这是一个把戏。 注释消除了对该技巧的需要,并保留了接口的协定角色。
publicclassFooimplementsMarkerInterface{} (1) @MyAnnotation publicclassFoo{} (2)
- 标记界面
- 等同于标记界面的注释
-
弃用是将API标记为过时的过程。 这样,用户可以获知有关更改的信息,可以决定停止使用该API,并且可以在以后的版本中以较小的影响删除该API。 在Java 5之前,JavaDoc中设置了弃用:
/** * Blah blah JavaDoc. * * @deprecated As of JDK version 1.1, */ publicclassDeprecatedApi{}
显然,这是一种非常脆弱的方法:唯一利用它的方法是通过
javadoc
工具。 标准JavaDocs 专门讨论了这些不推荐使用的API 。 或者,可以通过自定义doclet配置javadoc
工具,以以任何所需方式处理Javadoc元数据(包括但不限于@deprecated
)。在Java 5中,已弃用使用提供的
@Deprecated
批注进行标记:/** * Blah blah JavaDoc. */ @Deprecated publicclassDeprecatedApi{}
旧的不推荐使用的API保留了旧的方法,因此它们同时使用元数据和注释。
此外,由于Java 9,
@Deprecated
允许两个元素:可选元素 修饰符和类型 描述 forRemoval
boolean
Indicates whether the annotated element is subject to removal in a future version.
since
String
Returns the version in which the annotated element became deprecated.
@Deprecated(since="1.2",forRemoval=true) publicabstractclassIdentityScopeextendsIdentity{
标记器接口
更好的元数据管理
创建注释
要创建注释,请使用@interface
关键字:
public@interfaceMyAnnotation{}
但是,这还不够,因为不能在任何地方设置这样的注释。 注释需要另外两条信息:
- 目标 :定义可以在何处设置注释
- 保留 :这说明了注释在编译过程中的哪个步骤可用
稍后我们将详细介绍。 到目前为止,我们首先需要了解注释的工作方式。 当类从其父类继承代码时,将注解为 。
@Target(ElementType.ANNOTATION_TYPE) (1)
@interfaceFoo{}
@Target(ElementType.ANNOTATION_TYPE) (1)
@interfaceBar{}
@Foo
@Bar
@interfaceBaz{} (2)
- 这是必需的
@Target
,将在@Target
进一步解释 - 用
@Baz
注释的内容同时用@Foo
和@Bar
注释
这是@Target
和@Retention
的源代码:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public@interfaceTarget{
(1)
ElementType[]value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public@interfaceRetention{
(2)
RetentionPolicyvalue();
}
-
@Target
注释告诉您可以在哪个元素上设置注释:- 在类型上, 例如类或接口
- 在另一个注释上
- 在田野上
- 在方法上
- 在构造函数上
- 在方法参数上
- 在局部变量上
- 在模块上
- 等等
-
@Retention
注释定义了注释在编译过程中的哪个步骤可用:- 仅源代码
- 在类文件中
- 在运行时
下面的类图中对此进行了总结:
注释参数
注释可以定义参数 。 使用注释时,可以使用参数添加某些级别的配置。 参数接受类型和可选的默认值 。 如果在定义注释时未设置该值,则必须在使用它时使用。
参数类型限于以下几种:
- 任何原始类型, 例如
int
,long
等。 -
String
-
Class<T>
- 任何
enum
类型 - 另一种注释类型
- 以上任何数组
@Target(ElementType.CLASS)
@interfaceFoo{
intbar();
Class<?extendsCollection>baz()defaultList.class;
String[]qux();
}
@Foo(bar=1,qux={
"a","b","c"})
classMyClass{}
如果只有一个参数并将其命名为value
,则在设置时可以省略其名称:
@Target(ElementType.CLASS)
@interfaceFoo{
intvalue();
}
@Foo(1)
classMyClass{}
在运行时处理批注:反射
自创建以来,Java就允许反射 :反射是在运行时获取有关代码信息的能力。 这是一个示例:
varsession=request.getHttpSession();
varobject=session.getAttribute("objet"); (1)
varclazz=object.getClass(); (2)
varmethods=clazz.getMethods(); (3)
for(varmethod:methods){
if(method.getParameterCount()==0){
(4)
method.invoke(foo); (5)
}
}
- 获取存储在会话中的对象
- 获取对象的运行时类
- 获取对象上所有可用的
public
方法 - 如果该方法没有参数
- 调用方法
通过注释,反射API得到了相关的改进:
通过注释,框架开始在不同的用例中使用它们。 其中,配置是最常用的配置之一:例如, Spring框架代替了XML(或者更精确地说,除了XML之外),还添加了基于注释的配置选项。
在编译时处理批注:批注处理器
长期以来,用户和提供者都对运行时反射对批注的访问感到满意。 因为它主要集中在配置上,所以反射在启动时发生。 在受限的环境中,这对应用程序来说负担太重:此类环境最著名的示例是Android平台。 人们可能希望在那里拥有最快的启动时间,而启动时间反射方法会使速度变慢。
解决该问题的另一种方法是在编译时处理注释 。 为此,必须将编译器配置为使用特定的注释处理器 。 它们的输出可能不同:简单的文件,生成的代码等。这种方法的权衡之处在于, 每次编译都会对性能造成影响,但不会影响启动时间。
使用此方法生成代码的最早框架之一是Dagger :它是Android的DI框架。 它不是基于运行时的,而是基于编译时的。 长期以来,编译时代码生成仅限于Android生态系统。
但是,最近,诸如Quarkus和Micronaut之类的后端框架也采用了这种方法。 目的是通过编译时代码生成来代替运行时自省,以减少应用程序启动时间。 此外,将生成的字节码提前编译为本机代码还可以进一步减少启动时间以及内存消耗。
注释处理器的世界非常庞大:本节只是一个很小的介绍,因此如果需要,可以继续进行。
处理器只是需要在编译时注册的特定类。 有几种注册方法。 使用Maven,只需配置编译器插件即可:
<build>
<plugins>
<plugin>
<groupId> org.apache.maven.plugins </groupId>
<artifactId> maven-compiler-plugin </artifactId>
<version> 3.8.1 </version>
<configuration>
<annotationProcessors>
<annotationProcessor> ch.frankel.blog.SampleProcessor </annotationProcessor>
</annotationProcessors>
</configuration>
</plugin>
</plugins>
</build>
处理器本身需要实现Processor
,但是抽象类AbstractProcessor
实现其大多数方法,但可以进行process
:实际上,从AbstractProcessor
继承就足够了。 这是API的简化图:
让我们创建一个非常简单的处理器。 它只应列出带有特定注释的类。 现实世界中的注释处理器可能会做一些有用的事情, 例如生成代码,但是这种额外的逻辑远远超出了本文的范围。
@SupportedAnnotationTypes("ch.frankel.blog.*") (1)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
publicclassSampleProcessorextendsAbstractProcessor{
@Override
publicbooleanprocess(Set<?extendsTypeElement>annotations, (2)
RoundEnvironmentenv){
annotations.forEach(annotation->{
(3)
Set<?extendsElement>elements=env.getElementsAnnotatedWith(annotation); (4)
elements.stream()
.filter(TypeElement.class::isInstance) (5)
.map(TypeElement.class::cast) (6)
.map(TypeElement::getQualifiedName) (7)
.map(name->"Class "+name+" is annotated with "+annotation.getQualifiedName())
.forEach(System.out::println);
});
returntrue;
}
}
- 属于
ch.frankel.blog
包的每个注释都将调用处理器 -
process()
是重写的主要方法 - 将为每个注释调用循环
- 注释不像使用注释的元素那么有趣。 这是获取带注释元素的方法。
- 根据要注释的元素,需要将其强制转换为正确的
Element
子接口。 在这里,只能注释类,因此,需要对变量进行测试,以检查其是否可分配的TypeElement
才能在操作链的更下方访问其附加属性。 - 我们希望设置注释的类的合格名称,因此有必要将其强制转换为可访问此特定属性的类型
- 从
TypeElement
获取合格名称
结论
无论在运行时还是在编译时使用,注释都非常强大。 另一方面,最大的问题是它们似乎像魔术一样工作:没有简单的方法来知道哪个使用反射的类或注释处理器正在使用它们。 每个人都可以根据自己的情况决定自己的优点是否超过缺点。 在没有任何深思熟虑的情况下使用它们会对代码产生极大的损害….由于意识形态错位而导致丢弃它们与破坏代码一样严重。
我希望这篇文章对注释的工作方式有所启发,以便大家自己决定。
可以在
Github上以Maven格式找到此帖子的完整源代码。
翻译自: https://blog.frankel.ch/introductory-guide-annotation-processor/
批处理注释bat注释一行
今天的文章批处理注释bat注释一行_注释和注释处理器入门指南分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/4979.html