Java Annotation.equals()与Object.equals()的比较

Java Annotation.equals()与Object.equals()的比较,java,annotations,equals,guice,hashcode,Java,Annotations,Equals,Guice,Hashcode,某些框架(例如)在某些情况下需要创建注释接口的实现类 在这种情况下,需要遵守的和定义之间似乎存在差异(同样适用于) 问题: 为什么设计成这样?差异的原因是什么 使用注释类的Object.equals(Object)定义时会产生什么副作用 更新: 其他问题: 定义是什么?是否真的需要以这种方式实现它,特别是“(…)127倍于String.hashCode()计算的成员名哈希代码或哈希代码(…)”部分 如果实现的hashCode()方法与equals()一致,但与Annotation.hash

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

在这种情况下,需要遵守的和定义之间似乎存在差异(同样适用于)

问题:

  • 为什么设计成这样?差异的原因是什么
  • 使用注释类的
    Object.equals(Object)
    定义时会产生什么副作用
更新:

其他问题:

  • 定义是什么?是否真的需要以这种方式实现它,特别是“(…)127倍于String.hashCode()计算的成员名哈希代码或哈希代码(…)”部分

  • 如果实现的
    hashCode()
    方法与
    equals()
    一致,但与
    Annotation.hashCode()
    的确切定义不匹配(例如,使用128倍于成员名称的哈希代码),会发生什么情况


定义没有区别。
Annotation
中的定义只是专门针对注释类型

Object
中的定义基本上是“如果您决定为您的类实现
equals
,它应该表示遵循这些规则的等价关系”

Annotation
中,它定义了遵循这些规则的等价性,这对于
Annotation
实例特别有意义

事实上,
注释
等价性将适用于许多其他类。关键是不同的类有不同的含义,因此它们的实例可能有不同的等价关系,这取决于程序员决定对他/她的类使用哪种等价关系。在
注释
中,合同是针对这种特殊的等价关系的

至于副作用-假设
注释
类型继承的
对象
等于。当许多人试图在映射或其他依赖于
的情况下使用自己的类时,这是一个错误
Object
有一个与Object identity相同的
equals()
函数:两个引用只有在引用同一个对象时才相等

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


至于
hashCode
问题,尽管杰夫·鲍曼已经回答了这个问题,但为了让我的回答更完整,我将解决这个问题:

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

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

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

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


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

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

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

  • 您定义了一个接口(特别是注释)

  • 有人(javac)编写了该接口的特定(内置)实现。您无法访问该实现,但需要能够创建相等的实例,尤其是在集合和映射中使用。(毕竟,Guice是一张很大的
    地图。)

  • 实现者(javac)编写了一个equals的自定义实现,以便使用相同参数的注释实例