成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

How to Override Equals in Java and Scala

Kahn / 2805人閱讀

摘要:總之,在編寫(xiě)單個(gè)類(lèi)的方法時(shí)比較簡(jiǎn)單,當(dāng)涉及子類(lèi)繼承時(shí),就要多考慮一下了。另外不要忘記覆蓋方法哦。

相信讀過(guò) 《Effective Java》 的讀者都已經(jīng)知道編寫(xiě) equals 方法的作用與重要性,基本概念不多做解釋?zhuān)@里就總結(jié)一下如何編寫(xiě)正確的 equals 方法。

equals 在 Java 和 Scala 中含義相同,都需要滿(mǎn)足以下五個(gè)條件:

自反性

對(duì)稱(chēng)性

傳遞性

一致性

anyObject.equals(null) == false

現(xiàn)在我們有三個(gè)問(wèn)題:

假如我們只有一個(gè)類(lèi) Person,如何寫(xiě)?

假如 Person 類(lèi)有一個(gè)子類(lèi) Student,相互不能判斷(一定返回 false),如何寫(xiě)?相互可以判斷,如何寫(xiě)?

假如 PersonStudent 可以相互判斷,但另一子類(lèi) Teacher 只能和同類(lèi)判斷,如何寫(xiě)?

Java

《Effective Java》 中最后推薦的寫(xiě)法步驟是:

通過(guò) == 判斷是否是同一個(gè)對(duì)象

instanceof 判斷是否是正確的類(lèi)型,注意這里已經(jīng)包含了 null 的情況,所以不用多帶帶另寫(xiě)

將對(duì)象轉(zhuǎn)換成正確的類(lèi)型

對(duì)需要判斷的域分別進(jìn)行對(duì)比

需要注意,基本類(lèi)型用 == 判斷,例外是 floatFloat.comparedoubleDouble.compare,因?yàn)橛?NaN 等特殊值存在。

上述第二步中還有另一個(gè)變種,是使用 getClass 進(jìn)行類(lèi)型判斷,這樣的話(huà)只有類(lèi)型完全一致才能返回 true,如果只是單一的類(lèi)還好,要是涉及類(lèi)之間的繼承,則違背了 Liskov Substitution Principle,所以最后書(shū)中的結(jié)論是:

There is no way to extend an instantiable class and add a value component while preserving the equals contract.

由于現(xiàn)在的 IDE 例如 IntelliJ IDEA 已經(jīng)可以自動(dòng)為我們生成 equals 方法,還可以選擇是否允許子類(lèi)判斷,是否可為 null 等判斷,所以我們就不必手動(dòng)編寫(xiě)了,但是生成的結(jié)果也是符合上面的 4 步的:

class Person{
    private String name;
    private int age;

    @Override 
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) { // 不涉及繼承,問(wèn)題 1 和 問(wèn)題 2 前半的寫(xiě)法
            return false;
        }

        Person person = (Person) o;

        if (age != person.age) {
            return false;
        }
        return name != null ? name.equals(person.name) : person.name == null;
    }
    
    @Override 
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Person)) { // 涉及繼承,使得與子類(lèi)之間也可以判斷,問(wèn)題 2 后半的寫(xiě)法
            return false;
        }

        Person person = (Person) o;

        if (age != person.age) {
            return false;
        }
        return name != null ? name.equals(person.name) : person.name == null;
    }
}
Scala

scala 中編寫(xiě)的方式大致相同,但是結(jié)合其語(yǔ)法,相比似乎又簡(jiǎn)單又繁瑣。
簡(jiǎn)單是指當(dāng)沒(méi)有子類(lèi),或和子類(lèi)判斷一定為 false 時(shí)(違反LSP),可以這樣寫(xiě):

class Person(val name: String, val age: Int) { 
  override def equals(other: Any): Boolean = other match { // 問(wèn)題 1 的寫(xiě)法
    case that: this.getClass == that.getClass &&
                Person => name == that.name && 
                age == that.age
    case _ => false
  }
}

繁瑣是指假如這時(shí)出現(xiàn)了一個(gè)子類(lèi) Student 且增加了一個(gè)域 sid,假如我們需要兩個(gè)類(lèi)可相互判斷,則上述方法在判斷一個(gè) Person 對(duì)象和一個(gè) Student 對(duì)象時(shí)一定會(huì)返回 false

因此《Programming in Scala》中建議采用如下的編寫(xiě)方式:

class Person(val name: String, val age: Int) {
  def canEqual(other: Any): Boolean = other.isInstanceOf[Person]

  override def equals(other: Any): Boolean = other match { // 問(wèn)題 2 的寫(xiě)法
    case that: Person =>
      (that canEqual this) &&
        name == that.name &&
        age == that.age
    case _ => false
  }
}

class Student(override val name: String, override val age: Int, val sid: Int) extends Person(name, age){
}

上面 canEqual 方法的作用和 Java 代碼中判斷 instanceof 的作用是一致的,但比 Java 中的判斷更加靈活,比如可以限定不同子類(lèi)與父類(lèi)的判斷關(guān)系。

比如有一個(gè) Person 的子類(lèi) Teacher,我們希望它只能和 Teacher 類(lèi)進(jìn)行判斷,與 PersonStudent 判斷都返回 false,該如何寫(xiě)呢?一種錯(cuò)誤的寫(xiě)法如下:

class Teacher(override val name: String, override val age: Int, val tid: Int) extends Person(name, age){
  override def equals(other: Any): Boolean = other match {
    case that: Teacher =>
      this.getClass == that.getClass &&
        name == that.name &&
        age == that.age
    case _ => false
  }
}

val s1 = new Student("z", 1, 2)
val t1 = new Teacher("z", 1, 2)
println(s1 == t1) // true
println(t1 == s1) // false 違反了對(duì)稱(chēng)性

正確的寫(xiě)法應(yīng)該是:

class Teacher(override val name: String, override val age: Int, val tid: Int) extends Person(name, age){
  override def canEqual(other: Any): Boolean = other.isInstanceOf[Teacher]

  override def equals(other: Any): Boolean = other match { // 問(wèn)題 3 的寫(xiě)法
    case that: Teacher =>
      super.equals(that) &&
        (that canEqual this) &&
        name == that.name &&
        age == that.age &&
        tid == that.tid
    case _ => false
  }
}

注意只覆蓋了 canEqual 方法也會(huì)違反對(duì)稱(chēng)性。在 Java 中要實(shí)現(xiàn)相同的效果,則也需要編寫(xiě)類(lèi)似的 canEqual 方法,就留給讀者自己考慮了。

總之,在編寫(xiě)單個(gè)類(lèi)的 equals 方法時(shí)比較簡(jiǎn)單,當(dāng)涉及子類(lèi)繼承時(shí),就要多考慮一下了。

另外不要忘記覆蓋 hashcode 方法哦。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68055.html

相關(guān)文章

  • 《Kotlin 極簡(jiǎn)教程 》第4章 基本數(shù)據(jù)類(lèi)型與類(lèi)型系統(tǒng)

    摘要:本章我們來(lái)學(xué)習(xí)一下的基本數(shù)據(jù)類(lèi)型與類(lèi)型系統(tǒng)。字符串就是一個(gè)抽象數(shù)據(jù)類(lèi)型。如果程序語(yǔ)言的語(yǔ)法中含有類(lèi)型標(biāo)記,就稱(chēng)該語(yǔ)言是顯式類(lèi)型化的,否則就稱(chēng)為隱式類(lèi)型化的。但是,可以把中對(duì)應(yīng)的這幾種基本數(shù)據(jù)類(lèi)型,理解為的基本類(lèi)型的裝箱類(lèi)。 第4章 基本數(shù)據(jù)類(lèi)型與類(lèi)型系統(tǒng) 《Kotlin極簡(jiǎn)教程》正式上架: 點(diǎn)擊這里 > 去京東商城購(gòu)買(mǎi)閱讀 點(diǎn)擊這里 > 去天貓商城購(gòu)買(mǎi)閱讀 非常感謝您親愛(ài)的讀...

    MoAir 評(píng)論0 收藏0
  • Scala類(lèi)型推導(dǎo)

    摘要:提供了類(lèi)型推導(dǎo)來(lái)解決這個(gè)問(wèn)題。函數(shù)式語(yǔ)言里比較經(jīng)典的類(lèi)型推導(dǎo)的方法是,并且它是在里首先使用的。的類(lèi)型推導(dǎo)有一點(diǎn)點(diǎn)不同,不過(guò)思想上是一致的推導(dǎo)所有的約束條件,然后統(tǒng)一到一個(gè)類(lèi)型上。而推導(dǎo)器是所有類(lèi)型推導(dǎo)器的基礎(chǔ)。 Scala類(lèi)型推導(dǎo) 之劍 2016.5.1 00:38:12 類(lèi)型系統(tǒng) 什么是靜態(tài)類(lèi)型?為什么它們很有用? 根據(jù)Picrce的說(shuō)法:類(lèi)型系統(tǒng)是一個(gè)可以根據(jù)代碼段計(jì)算出來(lái)的值對(duì)...

    SQC 評(píng)論0 收藏0
  • Kotlin框架巡禮

    摘要:框架官方支持的框架,風(fēng)格頗為類(lèi)似,并且充分發(fā)揮了的強(qiáng)類(lèi)型優(yōu)勢(shì)。這是一個(gè)主要面向的框架,為提供了一些額外特性。依賴(lài)注入框架用法簡(jiǎn)單,支持等特性。 首先要說(shuō)明,Kotlin支持你所知道的所有Java框架和庫(kù),包括但不限于Spring全家桶、Guice、Hibernate、MyBatis、Jackson等,甚至有人在用Kotlin寫(xiě)Spark大數(shù)據(jù)程序,因此Kotlin不需要專(zhuān)門(mén)的框架。因此...

    _Suqin 評(píng)論0 收藏0
  • Start Using Java Lambda Expressions(轉(zhuǎn)載)

    摘要:原文 Introduction (Business Case) Lambda expressions are a new and important feature included in Java SE 8. A lambda expression provides a way to represent one method interface using an expression...

    FullStackDeveloper 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<