软件构造笔记----ADT和OOP中的“等价性”

8 Equality in ADT and OOP
ADT和OOP中的“等价性”

Java基础知识:

覆写Object方法

因为所有的class最终都继承自Object,而Object定义了几个重要的方法:

  • toString():把instance输出为String
  • equals():判断两个instance是否逻辑相等;
  • hashCode():计算一个instance的哈希值。

在必要的情况下,我们可以覆写Object的这几个方法。例如:

class Person {
    ...
    // 显示更有意义的字符串:
    @Override
    public String toString() {
        return "Person:name=" + name;
    }

    // 比较是否相等:
    @Override
    public boolean equals(Object o) {
        // 当且仅当o为Person类型:
        if (o instanceof Person) {
            Person p = (Person) o;
            // 并且name字段相同时,返回true:
            return this.name.equals(p.name);
        }
        return false;
    }

    // 计算hash:
    @Override
    public int hashCode() {
        return this.name.hashCode();
    }
}

调用super

在子类的覆写方法中,如果要调用父类的被覆写的方法,可以通过super来调用。例如:

class Person {
    protected String name;
    public String hello() {
        return "Hello, " + name;
    }
}

Student extends Person {
    @Override
    public String hello() {
        // 调用父类的hello()方法:
        return super.hello() + "!";
    }
}

final

继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。用final修饰的方法不能被Override

class Person {
    protected String name;
    public final String hello() {
        return "Hello, " + name;
    }
}

Student extends Person {
    // compile error: 不允许覆写
    @Override
    public String hello() {
    }
}

如果一个类不希望任何其他类继承自它,那么可以把这个类本身标记为final。用final修饰的类不能被继承:

final class Person {
    protected String name;
}

// compile error: 不允许继承自Person
Student extends Person {
}

对于一个类的实例字段,同样可以用final修饰。用final修饰的字段在初始化后不能被修改。例如:

class Person {
    public final String name = "Unamed";
}

final字段重新赋值会报错:

Person p = new Person();
p.name = "New Name"; // compile error!

可以在构造方法中初始化final字段:

class Person {
    public final String name;
    public Person(String name) {
        this.name = name;
    }
}

这种方法更为常用,因为可以保证实例一旦创建,其final字段就不可修改。

相等关系

相等关系是一种等价关系,即满足自反、对称、传递

可以用"是否为等价关系"来检验equals()是否正确

Immutable类型的相等
1.判相等要从A空间来看(用户角度) AF映射到相同结果,则等价

2.站在外部观察者角度:对两个对象调用任何相同的操作,都会得到相同的结果,则认为这两个对象是等价的。

== vs. equals()
1.== 表示的是引用等价性(一般用于基本数据类型的相等判定)

==操作符会比较引用。它测试参考等式。如果两个引用指向内存中的相同存储器,则它们是==。在快照图中,如果两个引用的箭头指向同一个对象气泡,则这两个引用为==(如果用==,是在判断两个对象身份标识 ID是否相等(指向内存里的同一段空间) )

2.equals()表示的是对象等价性 (用于对象类型相等判定)
在自定义ADT时,需要重写Object 的 equals() 方法

equals()方法的实现(Equality of Immutable Types)
在Objects中实现的缺省equals()是在判断引用相等性(相当于==);

在java中编写equal方法时需要注明@override,帮助检测标签是否正确;

用instanceof操作可以判断对象是否是一种特殊的类型(用instanceof是一种动态类型检查,而不是静态类型检查);

注意:不能在父类中用instanceof判断子类类型

除非对象被修改了,否则调用多次equals应同样的结果

等价的对象必须拥有相同的hashCode;不相等的对象也可以映射为同样的hashCode,但是性能会变差
重写equals方法必须要重写hashCode方法(除非能保证你的ADT不会被放入到Hash类型的集合中)

在这个例子中,d1和d2是相等的,但它们有不同的哈希码。确保满足契约的一个简单而激烈的方法是,hashCode总是返回一些常量值,因此每个对象的哈希代码都是相同的。

改进方法如下:


mutable类型的相等
观察等价性:在不改变状态的情况下,两个mutable对象是否看起来一致

行为等价性:调用对象的任何方法都展示出一致的结果

对于mutable类型来说,往往倾向于实现严格的观察等价性(但是在有些时候,观察等价性可能导致bug,甚至破坏RI)

注意:如果某个mutable的对象包含在Set集合类中,当其发生改变后,集合类的行为不确定!

Collections 使用的是观察等价性,但是其他的mutable类(如StringBuilder)使用的是行为等价性

对mutable类型,实现行为等价性即可。也就是说只有指向同样内存空间的objects,才是相等的,所以对mutable类型来说,无需重写这两个函数,直接调用Object的两个方法即可。(如果一定要判断两个对象"看起来"是否一致,最好定义一个新方法,e.g. similar() )

immutable类型必须重写equals() 和 hashCode()
mutable类型可以不重写,直接继承自Object
clone()
clone()创建并返回对象的一个copy

Autoboxing
Integer 和 int 注意区别

flase

(Numbers between -128 and 127 are true.)
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值