软件构造.Equality in ADT and OOP,== vs. equals()

Three Ways to Regard Equality

1.使用抽象函数
回想一下抽象函数AF:R→A将数据类型的具体实例映射到它们对应的抽象值。要使用AF作为相等的定义,我们会说当且仅当AF(a)= AF(b)时,a等于b
2.使用关系判断
在这里插入图片描述
3.从观察者角度
从观察的角度 ,对两个对象的任何同一操作都会得到相同的结果

== vs. equals()

java默认由hashcode()来提供判断依据
==是对于是否指向相同内容的判断
equals()是对于对象是否相等的判断

在这里插入图片描述
eg
在这里插入图片描述
在这里插入图片描述

Integer中的equals方法被重写了

equals()的源码

the default meaning of equals() is the same as referential equality. For immutable data types, this is almost always wrong. So you have to override the equals() method, replacing it with your own implementation.

public class Object {
    ...
    public boolean equals(Object that) {
        return this == that;
    }
}

equals改写1:

public class Duration {
    ...   
    // Problematic definition of equals()
    public boolean equals(Duration that) {
        return this.getLength() == that.getLength();        
    }
}

example:

public class Duration {
    private final int mins;
    private final int secs;
    // Rep invariant:
    //    mins >= 0, secs >= 0
    // Abstraction function:
    //    AF(min, secs) = the span of time of mins minutes and secs seconds

    /** Make a duration lasting for m minutes and s seconds. */
    public Duration(int m, int s) {
        mins = m; secs = s;
    }
    /** @return length of this duration in seconds */
    public long getLength() {
        return mins*60 + secs;
    }
}
public class Duration {
    ...   
    // Problematic definition of equals()
    public boolean equals(Duration that) {
        return this.getLength() == that.getLength();        
    }
}

问题如下

Duration d1 = new Duration (1, 2);
Duration d2 = new Duration (1, 2);
Object o2 = d2;
d1.equals(d2)true
d1.equals(o2)false

内存快照如下,一个对象是Object的,另一个对象是Duration的!!!

在这里插入图片描述

因为o2是Object类型的,父类Object中的equals的签名中参数为Object的,但是子类的签名中的参数为Duration,所以第二次判断的时候调用了父类的方法

改进

@Override
public boolean equals(Object that) {
    return that instanceof Duration && this.sameValue((Duration)that);
}

private static final int CLOCK_SKEW = 5; // seconds

// returns true iff this and that represent the same abstract value within a clock-skew tolerance
private boolean sameValue(Duration that) {
    return Math.abs(this.getLength() - that.getLength()) <= CLOCK_SKEW;
}

instanceof 因为是动态检查所以不推荐使用

Hashcode

大部分语言中都是采用对象的内存地址作为默认hashcode,但是java对于可变类型数据eglist,list add元素之后hashcode会改变

java中默认由hashCode()提供equals的判断依据
eg重写哈希表
比忘了写@Override

@Override
public int hashCode() {
    return (int) getLength();
}

Equality of Mutable Types

List<String> list = new ArrayList<>();
list.add("a");

Set<List<String>> set = new HashSet<List<String>>();
set.add(list);

内存快照
因为List经过了修改所有导致了哈希值的改变
在这里插入图片描述

set.contains(list)true
list.add("goodbye");
set.contains(list)false!
for (List<String> l : set) { 
    set.contains(l)false! 
}

内存快照
在这里插入图片描述

The Final Rule for equals() and hashCode()

不可 变类型应该重写equals()和hashCode()
可变类型不应该重写equals()和hashCode() ,采用Object默认实现的即可。

Autoboxing and Equality

Integer的这种初始化方式相当于创建了两个新对象,不涉及常量池

原因:Integer的equals实现了对对象内容是否相等的判读 而equals只是判断了引用是否相同

在这里插入图片描述
这种初始化方式涉及到了常量池,-127到127之间的数能保存在内存中,并且都指向同一地址
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值