简体   繁体   English

等价方法中的等价

[英]Equivalence in equals method

Why not Integer.valueOf(42).equals(Long.valueOf(42)) ? 为什么不Integer.valueOf(42).equals(Long.valueOf(42)) Whether implementation of equals must be "reflexive, symmetric, transitive, consistent" but don`t have to be reasonable? equals实现必须是“反身,对称,传递,一致”,但不必合理吗? :) :)

From the docs for Integer.equals() : 来自Integer.equals()的文档:

The result is true if and only if the argument is not null and is an Integer object that contains the same int value as this object. 当且仅当参数不为null并且是包含与此对象相同的int值的Integer对象时,结果才为真。

In other words, an Integer will never test as equals() to a Long (or anything else that's not an Integer ), regardless of the value being represented. 换句话说,无论表示什么值, Integer都不会测试为Long (或其他任何不是Integer )的equals() Just compare the primitive values if that's what you're after. 只需比较原始值,如果这就是你所追求的。

One good reason for not allowing cross-class comparisons is: how would you do it? 不允许跨类比较的一个很好的理由是:你会怎么做? Suppose you decided to implement Integer.equals() to test whether the other object was an instance of Number and compare values using other.intValue() (which all Number classes support). 假设您决定实现Integer.equals()来测试另一个对象是否是Number的实例,并使用other.intValue() (所有Number类支持)比较值。 The unfortunate result would be that 不幸的结果就是那样

Integer.valueOf(42).equals(Long.valueOf(((Integer.MAX_VALUE + 1L) << 1) + 42))

would test true because Long.intValue() simply casts its value to an int and 将测试为true因为Long.intValue()只是将其值转换为int

(int) ((Integer.MAX_VALUE + 1L) << 1) + 42)

evaluates to 42 because that's what's in the lower 32 bits. 评估为42,因为这是低32位的内容。 What's perhaps even worse, if you used the same logic for Long.equals() (where it tested all Number objects used longValue() ), then the equals() test would no longer be symmetric. 更糟糕的是,如果你对Long.equals() (使用longValue()测试了所有Number对象Long.equals()使用相同的逻辑,那么equals()测试将不再是对称的。

A reminder that Integer and Long are object wrapper classes of the primitive types int and long . 提醒一下, IntegerLong是原始类型intlong对象包装类。

Here is the source code of the equals method in Integer ( value here is an int primitive). 这是Integer equals方法的源代码(这里的value是一个int原语)。

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

And here is the source code of the equals method in Long ( value here is a long primitive). 这里是Long equals方法的源代码(这里的value是一个long原语)。

public boolean equals(Object obj) {
    if (obj instanceof Long) {
        return value == ((Long)obj).longValue();
    }
    return false;
}

From the source, the equals method firstly checks if the passed-in obj is an instance of the corresponding class. 从源代码开始, equals方法首先检查传入的obj是否是相应类的实例。 If it isn't, equals skips the check on the primitive value and returns false . 如果不是,则equals跳过对原始value的检查并返回false

So as @Ted Hopp suggested, an Integer will never test as equal to a Long (or anything else that's not an Integer ). 因此,正如@Ted Hopp建议的那样, Integer永远不会测试等于Long (或其他任何不是Integer )。 Comparing primitive values is recommended. 建议比较原始值。

If you nonetheless would like to carry out the equivalence check in the object wrapper setting, then you may wish to widen your Integer (avoiding an overflow) and let the Java compiler do some auto-(un)boxing for you. 如果您仍希望在对象包装器设置中执行等效检查,那么您可能希望扩展整数(避免溢出)并让Java编译器为您执行一些自动(非)装箱 Something like... 就像是...

Long theLong = Long.valueOf(42);
Integer theInteger = Integer.valueOf(42);
Long theIntegerInLong = (long) theInteger;
System.out.println(theLong.equals(theIntegerInLong) ? "Equal" : "Unequal");

.equals() is for comparisons between objects in the same inheritance hierarchy, up to and including the ultimate superclass Object. .equals()用于比较同一继承层次结构中的对象,包括最终的超类Object。 While classes Integer and Long both inherit from java.lang.Number, class Number is apparently missing an .equals() method that compares a Number instance value. 虽然类Integer和Long都继承自java.lang.Number,但类Number显然缺少一个比较Number实例值的.equals()方法。 Integer and Long's only shared .equals() method is in Object. Integer和Long唯一共享的.equals()方法在Object中。 The Object-to-Object comparison method does not evaluate based on the values of the numbers, hence the seemingly strange result printed. 对象 - 对象比较方法不基于数字的值进行评估,因此打印出看似奇怪的结果。

The documentation for class Integer says: .equals(): "The result is true if and only if the argument is not null and is an Integer object that contains the same int value as this object." 类Integer的文档说:.equals():“当且仅当参数不为null并且是包含与此对象相同的int值的Integer对象时,结果才为真。” It doesn't handle Long values as more than Objects. 它不像对象那样处理Long值。

Apparently as per @David_Wallace, other class hierarchies implement .equals() in their superclass. 显然,根据@David_Wallace,其他类层次结构在其超类中实现.equals()。 new ArrayList().equals(new LinkedList()) returns true, and both inherit from class java.util.AbstractList which has its own implementation of .equals() new ArrayList()。equals(new LinkedList())返回true,并且都从类java.util.AbstractList继承,它有自己的.equals()实现

It would have been possible to define the equality tests among wrapper classes in such a fashion that two wrapper objects that encapsulated the same numerical value would compare equal, regardless of the underlying type. 可以在这样的方式中定义包装类之间的相等性测试,即封装相同数值的两个包装器对象将比较相等,而不管底层类型如何。 Doing so, however, requires either having all types whose instances may compare equal know about each other, or else requires defining a means via which objects will be able to compare themselves to other objects which haven't even been invented yet. 但是,这样做要求要求所有类型的实例可以比较彼此相同,或者需要定义一种方法,通过该方法,对象可以将自己与尚未发明的其他对象进行比较。 Taking the former approach would mean that even if a new numeric type was capable of representing the value 5, an Integer which equaled 5 could not report itself equal to an instance of the new type which also represented 5. Taking the latter approach would allow the new object to compare equal to an Integer with value 5, but would require adding enormous complexity for comparatively little benefit. 采用前一种方法意味着即使新的数字类型能够表示值5,等于5的Integer也不能报告自己等于也表示为5的新类型的实例。采用后一种方法将允许要比较的新对象等于值为5的Integer ,但是需要增加极大的复杂性才能获得相对较少的好处。

Suppose, for example, that one has defined both a BigDecimal and a BigRational class; 例如,假设一个人定义了BigDecimalBigRational类; the former stores numbers as a BigInteger along with a power-of-ten scaling factor; 前者将数字存储为BigInteger同时存储十个幂的比例因子; the latter stores a pair of BigInteger values which represent a reduced-form fraction. 后者存储一对BigInteger值,表示缩减形式的分数。 One could specify that all numeric values which represent rational numbers should be compared by converting them to BigRational and comparing the results. 可以指定表示有理数的所有数值都应该通过将它们转换为BigRational并比较结果来进行比较。 Since every rational number would have a unique representation, such a defined method of comparison would behave as an equivalence relation. 由于每个有理数都具有唯一的表示,因此这种定义的比较方法将表现为等价关系。 Unfortunately, it would be horrendously slow. 不幸的是,它会非常缓慢。 In most cases, it would make more sense to convert comparands into some other form, but trying to identify the best common form for arbitrarily combinations of types would be difficult. 在大多数情况下,将比较法转换为其他形式会更有意义,但是尝试识别任意类型组合的最佳常见形式将是困难的。 It's much easier to simply say being of different types is sufficient justification for the objects to be called "different". 简单地说,不同类型的对象被称为“不同”的充分理由要容易得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM