代码之家  ›  专栏  ›  技术社区  ›  MRalwasser

注释。equals()与Object.equals()

  •  2
  • MRalwasser  · 技术社区  · 10 年前

    一些框架(例如。 guice )在某些情况下需要创建 注释接口的实现类 .

    似乎有一个 差别 Annotation.equals(Object) Object.equals(Object) 在这种情况下需要遵守的定义(同样适用于 hashCode() ).

    问题:

    • 为什么要这样设计?差异的原因是什么?
    • 使用 Object.equals(对象) 注释类的定义?

    更新:

    其他问题:

    • 那么 Annotation.hashCode() 释义是否真的需要这样实施,特别是“ (…)127倍于String计算的成员名称的哈希代码。hashCode())对哈希代码进行异或(…) “-部分?

    • 如果 hashCode() 方法的实现与 equals() 但不符合 Annotation.hashCode() (例如,使用128倍于成员名称的哈希码)?

    3 回复  |  直到 10 年前
        1
  •  4
  •   RealSkeptic    10 年前

    定义没有不同。中的定义 Annotation 很简单 专业的 用于注释类型。

    中的定义 Object 基本上说“如果你决定实施 equals 对于您的类,它应该表示遵循这些规则的等价关系”。

    在里面 批注 它定义了遵循这些规则的等价关系,这对于 批注 实例。

    事实上 批注 等价性适用于许多其他类。重点是不同的类具有不同的含义,因此它们的实例可能具有不同的等价关系,由程序员决定要为其类使用哪个等价关系。在里面 批注 ,合同是针对这种特定的等价关系。

    至于副作用-假设 批注 继承的类型 对象 等于。这是许多人在尝试在地图或其他应用程序中使用自己的类时所犯的错误 equals() -依赖情况。 对象 有一个 equals() 与对象标识相同的函数:只有当两个引用是对同一对象的引用时,它们才相等。

    如果你使用了这个,那么没有两个实例会被认为是相同的。尽管它们的字段中具有相同的值,并且在语义上表示相同的行为类型,但您将无法创建与前一个实例等效的第二个Annotation实例。因此,当两个项目具有不同的注释时,您无法判断它们是否使用相同的注释进行注释 实例 同一注释。


    至于 hashCode 问题,虽然杰夫·鲍曼已经回答了这个问题,但我将解决这个问题,使我的答案更完整:

    基本上,注释的实现是留给编译器的,而JLS并不规定具体的实现。正如您的问题本身所提到的,也可以创建实现类。

    这意味着注释类可以来自不同的源-不同的编译器(您应该能够运行 .class 文件,无论是哪个java编译器创建的)和开发人员创建的实现。

    这个 equals() hashCode() 方法通常在单个类上下文中考虑,而不是在接口上下文中考虑。这是因为接口通常与实现相反——它们只定义契约。当您为特定类创建这些方法时,您知道与之比较的对象应该属于同一类,因此具有相同的实现。一旦它有了 哈希代码 方法,该方法为下等效的对象返回相同的值 等于 对于同一个类,那么无论实现是什么,它都满足约定。

    然而,在这种特殊情况下,您有一个接口,需要使equals()和hashcode()不仅适用于同一类的两个实例,而且适用于实现同一接口的不同类的实例。这意味着,如果您不同意所有可能的类中的一个实现,那么可能会得到具有相同元素值和不同哈希代码的同一注释的两个实例。这将打破 hashcode() 合同

    例如,想象一个注释 @SomeAnnotation 这不需要参数。想象一下,你用一个类来实现它 SomeAnnotationImpl 返回 15 作为哈希码。两个相等的实例 一些注释示例 将具有相同的哈希代码,这很好。但是Java编译器会返回 0 当您检查其自身实现的返回实例时 @Some注解 。因此,类型为 批注 相等(它们实现相同的注释接口,如果它们遵循 equals() 上面的定义,他们应该返回 true 对于 等于 ),但具有不同的哈希代码。这违反了合同。

        2
  •  2
  •   Jeff Bowman    10 年前

    Real怀疑论者的回答很好,但我会用稍微不同的方式来回答。

    这是一个一般问题的具体实例:

    1. 您定义了一个接口(特别是一个注释)。

    2. 有人(javac)编写了该接口的特定(内置)实现。您无法访问该实现,但需要能够创建相等的实例,尤其是在“集合”和“贴图”中使用。(Guice是一个大 Map<Key, Provider> 毕竟。)

    3. 实现者(javac)编写了一个equals的自定义实现,以便传递具有相同参数的注释实例 equals 。您需要匹配该实现,以便 等于 是对称的( a.equals(b) 当且仅当 b.equals(a) ,这在Java中与自反性、一致性和传递性一起假设)。

    4. 相等对象必须具有相等 hashCode 这是因为Java将其用作相等的快捷方式:如果对象具有不相等的hashCodes,则它们不能相等。这对于实现高效的Map实现HashMap非常有用,因为您可以使用 哈希代码 仅检查右侧的对象 哈希代码 -确定铲斗。如果使用不同的或修改的 哈希代码 算法,理论上你会违反规范,实际上你的注释实现在HashSet或HashMap中与其他实现不一致(这对Guice来说毫无价值)。许多其他功能使用hashCode,但这些是最明显的例子。

    5. 如果Java允许你实例化它们的实现,或者为你的类自动生成一个实现,这会容易得多,但在这里,他们所做的最好的就是为你提供一个精确的规范。

    所以,是的,你会比其他任何事情都更经常遇到注释,但每当你试图与自己无法控制或使用的实现保持一致时,这些都很重要。

        3
  •  0
  •   jwells131313    10 年前

    上面的答案是这个问题的很好的一般答案,但由于我没有看到它们被提及,我只想补充一点,使用AnnotationLiteral实现Annotations可以适当地处理equals和hashCode问题。有两种可供选择:

    AnnotationLiteral AnnotationLiteral