软件构造学习笔记(8) --ADT&&OOP的等价性

1. 等价关系 (Equivalence Relation)
  • 定义:等价关系E是满足以下条件的T x T的子集:
    • 自反性 (Reflexive):对所有T中的t,E(t, t)
    • 对称性 (Symmetric):如果E(t, u),则E(u, t)
    • 传递性 (Transitive):如果E(t, u)且E(u, v),则E(t, v)
  • 应用:使用等价关系E定义相等性,即a等于b当且仅当E(a, b)。
2. 等价性的三种考量方式
  • 抽象函数 (AF):将具体实例映射到相应的抽象值,a等于b当且仅当AF(a) = AF(b)。
  • 观察者角度:如果两个对象在所有可应用的操作下产生相同的结果,则它们被视为等价。
  • == 与 equals()
    • == 用于基本数据类型,检查引用等价性。
    • equals() 用于对象类型,检查对象内容等价性。
3. 实现 equals()
  • 默认行为:Object类中的equals()默认实现检查引用等价性。
  • 重写需求:对于不可变类型,通常需要重写equals()以实现基于抽象值的比较。
  • 注意事项
    • 使用@Override注解确保正确重写。
    • 避免使用instanceof,除非在实现equals()时。

这里具体展开来看一下equal:

实现equals()

  1. equals() 方法的重要性:

    • 在Java中,equals() 方法用于比较两个对象的内容是否相等,即对象等价性(object equality)。
    • 对于自定义的抽象数据类型(ADT),需要适当地定义equals(),以确定对象间何时视为等价。
  2. 默认的equals() 实现:

    • Object 类中,equals() 默认实现比较的是引用等价性(referential equality),即两个引用是否指向内存中的同一位置。
  3. 重写equals():

    • 对于不可变类型(immutable types),通常需要重写equals(),以实现基于抽象值的比较。
    • 重写时,应确保equals() 遵循等价关系的所有性质:自反性(reflexive)、对称性(symmetric)、传递性(transitive)。
  4. 使用 @Override 注解:

    • 使用@Override 注解来重写方法时,编译器会检查父类中是否存在相同签名的方法,确保正确重写。
  5. equals() 的一致性:

    • 重写equals() 时,必须保证在对象未被修改的情况下,多次调用equals() 返回的结果一致。
  6. equals() 与 instanceof:

    • 在equals() 方法中使用instanceof 是允许的,用于检查对象是否是特定类型的实例。
    • 但在面向对象编程中,通常应避免使用instanceof,因为它破坏了多态性。
  7. equals() 与 hashCode():

    • 当重写equals() 时,应同时重写hashCode(),以确保两个通过equals() 比较相等的对象,调用hashCode() 时返回相同的整数值。
    • 这是为了保持使用哈希表的数据结构(如HashSet和HashMap)的正确性。
  8. hashCode() 的实现:

    • hashCode() 的实现应考虑对象中用于确定等价性的所有组件,并计算出一个整数值。
    • Java提供了Objects.hash() 工具方法来简化涉及多个字段的hashCode() 的实现。
  9. equals() 的错误用法:

    • 错误地重载equals() 而非重写,会导致编译时类型检查失败,从而调用错误的方法实现。
  10. equals() 的一致性原则:

    • 必须保证equals() 实现是一个等价关系,否则依赖于等价性的操作(如集合搜索)将表现出不可预测的行为。

 

4. Object合同中的equals()
  • 合同要求
    • 自反性:每个对象都应等于自己。
    • 对称性:如果a.equals(b),则b.equals(a)。
    • 传递性:如果a.equals(b)且b.equals(c),则a.equals(c)。
    • 一致性:除非对象信息被修改,否则多次调用应返回相同结果。
    • 对于非空引用x,x.equals(null)应返回false。
    • 相等的对象必须有相同的hashCode。
5. hashCode() 合同
  • 要求
    • 多次调用hashCode()应返回相同整数值,前提是对象未被修改。
    • 相等的对象必须有相同的hashCode值。
    • 不要求不相等的对象有不同hashCode值,但这样可能影响哈希表性能。
6. 可变类型与不可变类型的等价性
  • 不可变类型
    • equals()应比较抽象值,即行为等价。
    • hashCode()应将抽象值映射为整数。
    • 必须重写equals()和hashCode()。
  • 可变类型
    • equals()应比较引用,即行为等价。
    • hashCode()应将引用映射为整数。
    • 不应重写equals()和hashCode(),使用Object的默认实现。
7. Autoboxing与等价性
  • 概念:基本类型和它们的包装类(如int和Integer)之间的自动转换。
  • 问题:Autoboxing可能导致意料之外的等价性判断。
8. 总结
  • 等价性是实现ADT的一部分,应为等价关系。
  • 等价性和hashCode必须一致,以确保如HashSet和HashMap这类使用哈希表的数据结构正常工作。
  • 抽象函数是不可变类型等价性的基础。
  • 引用等价性是可变类型等价性的基石,这是确保一致性并避免破坏哈希表RI的唯一方法。
  • 36
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值