Lecture 15: Equality

1 Three Ways to Regard Equality

  • Using an abstraction function: The function f is Absract Function. To use f as a definition for equality, we would say that a equals b if and only if f(a)=f(b).
  • Using a relation: E is an quivalence relation, we would say that a equals b if and only if E(a,b).
  • Using observation: Two objects are equal if and only if they cannot be distinguished by calling any operations of the abstract data type.

2 == vs. equals()

  • The == operator compares references. Two references are == if they point to the same storage in memory.
  • The equals() operation compares object contents.
referential equalityobject equality
Java==equals()
Objective C==isEqual:
C#==Equals()
Pythonis==
Javasript==n/a

Note that == unfortunately flips its meaning between Java and Python.

3 Equality of Immutable Types

It’s easy to make a mistake in the method signature, and** overload a method** when you meant to override it. This is such a common error that Java has a language feature, the annotation @Override , which you should use whenever your intention is to override a method in your superclass.

3.1 instanceof

  • Using instanceof is dynamic type checking, not the static type checking we vastly prefer. In general, using instanceof in object-oriented programming is a bad smell.
  • This is another of our rules that holds true in most good Java programming — instanceof is disallowed anywhere except for implementing equals . This prohibition also includes** other ways of inspecting objects’ runtime types**. For example, getClass is also disallowed.

4 The Object Contract

  • equals must define an equivalence relation – that is, a relation that is reflexive, symmetric, and transitive;
  • equals must be consistent: repeated calls to the method must yield the same result provided no information used in equals comparisons on the object is modified;
  • For a non-null reference x , x.equals(null) should return false;
  • hashCode must produce the same result for two objects that are deemed equal by the equals method.

Here are some counter examples:

  • Breaking the Equivalence Relation
private static final int CLOCK_SKEW = 5; // seconds

@Override
public boolean equals (Object thatObject) {
    if (!(thatObject instanceof Duration)) return false;
    Duration thatDuration = (Duration) thatObject;
    //breaking transitive
    return Math.abs(this.getLength() - thatDuration.getLength()) <= CLOCK_SKEW;
}
  • Breaking Hash Tables
    • Two very common collection implementations, HashSet and HashMap , use a hash table data structure, and depend on the hashCode method to be implemented correctly for the objects stored in the set and used as keys in the map.
    • How to implement hashCode(), see 《Effective Java》, Item 9.

Always override hashCode when you override equals.

5 Equality of Mutable Types

  • when they cannot be distinguished by observation that doesn’t change the state of the objects , i.e., by calling only observer, producer, and creator methods. This is often strictly called observational equality , since it tests whether the two objects “look” the same, in the current state of the program.
  • when they cannot be distinguished by any observation, even state changes. This interpretation allows calling any methods on the two objects, including mutators. This is often called** behavioral equality** , since it tests whether the two objects will “behave” the same, in this and all future states.

5.1 Solution

  • Mutable objects should just inherit equals() and hashCode() from Object . For clients that need a notion of observational equality (whether two mutable objects “look” the same in the current state), it’s better to define a new method, e.g., similar() .
  • equals() should compare references, just like == . Again, this is the same as saying equals() should provide behavioral equality.
  • hashCode() should map the reference into an integer.

6 Autoboxing and Equality

See code below:

Integer x = new Integer(3);
Integer y = new Integer(3);
x.equals(y) → true

and:

x == y // returns false
(int)x == (int)y // returns true

So you can’t really use Integer interchangeably with int . The fact that Java automatically converts between int and Integer (this is called autoboxing and autounboxing ) can lead to subtle bugs!


Reference

[1] 6.005 — Software Construction on MIT OpenCourseWare | OCW 6.005 Homepage at https://ocw.mit.edu/ans7870/6/6.005/s16/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值