有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java的原因是什么。lang.annotation。保持

我很清楚RetentionPolicy的含义,知道它们做什么,什么时候做。对于我自己的注释,我确切地知道它们是在运行时、类文件中还是仅仅用于编译。然而,对于库中定义的任何注释,您永远无法确定

例如,javax.annotation.Generated用于标记生成的代码,但很少有用。由于处理字节码的工具比处理源代码的工具多得多,因此信息在使用之前就消失了

由于运行时don't throwClassNotFoundException缺少注释(与缺少接口不同),使用RetentionPolicy.RUNTIME似乎不会造成伤害。还是我错了

还是说节省几个字节是使用不同Retention的原因?对我来说,这似乎造成了太多的问题,不值得这么做。我错过了什么


共 (3) 个答案

  1. # 1 楼答案

    Java注释的灵感出现在2002年之前,大约是从Java1.3过渡到Java1.4。当时的高规格桌面是2.5GHz左右的奔腾4或2GHz左右的Athlon XP+,RAM为256或512MB。例如一篇评论

    问题是如何存储和检索有关代码的元数据。典型的解决方案是使用未进行类型检查或未直接链接到源代码的XML文件。其他人已经非正式地为代码生成工具扩展了JavaDoc(源代码和扩展API出现在JDK中)。解决方案Annotations是一个扩展Javadoc和JLS类规范的hack(非常好的hack)

    很明显,最初的作者担心性能(在2002年,Java仍然相对缓慢,反射非常缓慢,Java运行时占用了大量内存;有些事情永远不会改变)。这是对JSR-175的介绍:

    Since many annotations will be used only by development tools such as stub generators, it makes little sense to retain all annotations at run time; doing so could increase run-time memory-footprint and harm performance. There are, however, some annotation types that are useful at run time, and some that are useful in tools that only have access to class files (not source files). Therefore, certain annotations are stored by the compiler in class file attributes (JVMS 4.7), and some of these annotations are then made available for inspection at runtime via new reflective APIs.

    他们解决问题的方法是将问题分为三个用例:

    VI. Reading annotations

    Annotation consumers may be divided into three groups:

    a. "Introspectors" - Programs that query runtime-visible annotations of their own program elements. These programs will load both annotated classes and annotation interfaces into the virtual machine. (By runtime-visible, we mean annotations whose retention policy is RUNTIME.)

    b. "Specific Tools" - Programs that query known annotation types of arbitrary external programs. Stub generators, for example, fall into this category. These programs will read annotated classes without loading them into the virtual machine, but will load annotation interfaces.

    c. "General Tools" - Programs that query arbitrary annotations of arbitrary external programs (such as compilers, documentation generators, and class browsers). These programs will load neither annotated classes nor annotation interfaces into the virtual machine. Such programs are said to operate "at arm's length."

    这使得(当时)上述定义的“特定工具”和“通用工具”的重要用例能够在不给运行时造成负担的情况下完成它们的工作;对于这些工具,注释可以是源代码,也可以是类。只有运行时需要的注释(从上面可以看出,这被认为是少数用例)才会加载并保留在JVM中

    因此,是的,保留策略是为了节省字节和运行时开销。虽然这看起来很奇怪,但2002年是一个不同的世界,内存和性能是非常现实的问题。现在我们有了10倍的性能和内存,您可以放心地使用运行时保留

  2. # 2 楼答案

    注释的主要目的是为编译单元携带元数据。大多数标准注释都清楚地表达了有助于代码开发和编译的元信息(通过指定可由IDE或编译器验证的属性)

    注释不是为修改语言的运行时语义而设计的。因此,注释在运行时是否可用本身不会改变执行。(当然,如果您主动地使用元信息来调整您的实现行为,那么一切都是可能的。)

    如果在库jar中的某个地方,注释被标记为RetentionPolicy.RUNTIME,那么很明显,从运行时访问注释(使用反射)对以后的用户很有用
    如果同时注释的实现来自另一个库,那么这种期望要么是没有保证的,要么是由于该注释的特定目的,可能只对某些用例有用。(当然,仅仅为不同的保留设置构建不同的jar版本是不合适的。)

    因此,如果开发人员将注释标记为RetentionPolicy.RUNTIME,那么在期望运行时访问的地方有一个明确的用例。注释实现是否使用相同的jar或不同的jar可能独立于用例(例如,基于其他结构化标准)。在任何情况下,如果您打算从这个用例中获益,那么在您的类路径中就会有这个注释库(因为您可能还需要其他组件),一切都很好。如果您不应用于此用例,那么您将不会受到缺少注释实现的影响

    改写你的问题:

    使用RUNTIME保留不会对程序造成任何伤害,只会使(字节码)可执行文件中的死信息变得混乱。只有在预期(并且认为有用)元信息的运行时使用时才使用RUNTIME保留增加了代码质量(在可维护性和可理解性方面)

  3. # 3 楼答案

    For example, javax.annotation.Generated is meant to mark generated code, but it's rarely useful. As there are AFAIK more tools working on the bytecode than tools working with the source, the information disappears just before it could be used.

    看看源代码编辑器,Android Studio源自JetBrains和许多其他IDE,需要处理源代码,它提供了所有伟大的编辑体验,只是因为编译时注释

    在编辑类(尚未编译)时,编辑器可以存储和处理注释

    例如:

    @SuppressWarnings让我们来抑制警告,否则怎么做?C#允许您定义#PRAGMA#IF,某种条件编译。编译输出中不存储任何条件编译信息

    @Override允许Java编译器检查基类是否有要重写的方法,如果您使用错误的参数定义新方法,Java编译器将使用重载的新方法编译类,但在存在@Override的情况下,Java编译器将给您一个错误,即签名与重写方法不正确匹配

    @GeneratedCode允许IDE跳过使用“查找和替换”搜索时显示的类和成员,并且它允许您仅对代码而不是生成的代码操作IDE。你有没有看过R.*Android中的资源,这些生成的类隐藏在Android Studio中,但它们确实提供了有用的代码完成列表

    类似地,许多这样的注释允许您进行代码分析、编写单元测试等,并在编译之前对其进行更多的工作

    这里有更多内容

    许多ORM框架使用编译时注释并生成有用的额外类,用于类型化查询和其他帮助器类,以创建表和维护模式

    结论

    在上面所示的示例中,很明显,所有三个和许多这样的注释都会添加很多字节,而这些字节在运行时是完全无用的

    Java有两种选择,一种是使用基于c语言中使用的#IFetc指令添加某种编译时注释。这将需要新的语法和新的编辑经验等,另一个是创建Retention。在不破坏语法的情况下创建Retention是一个不错的举动