国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

How to Override Equals in Java and Scala

Kahn / 2763人閱讀

摘要:總之,在編寫單個類的方法時比較簡單,當涉及子類繼承時,就要多考慮一下了。另外不要忘記覆蓋方法哦。

相信讀過 《Effective Java》 的讀者都已經知道編寫 equals 方法的作用與重要性,基本概念不多做解釋,這里就總結一下如何編寫正確的 equals 方法。

equals 在 Java 和 Scala 中含義相同,都需要滿足以下五個條件:

自反性

對稱性

傳遞性

一致性

anyObject.equals(null) == false

現在我們有三個問題:

假如我們只有一個類 Person,如何寫?

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

假如 PersonStudent 可以相互判斷,但另一子類 Teacher 只能和同類判斷,如何寫?

Java

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

通過 == 判斷是否是同一個對象

instanceof 判斷是否是正確的類型,注意這里已經包含了 null 的情況,所以不用多帶帶另寫

將對象轉換成正確的類型

對需要判斷的域分別進行對比

需要注意,基本類型用 == 判斷,例外是 floatFloat.comparedoubleDouble.compare,因為有 NaN 等特殊值存在。

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

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

由于現在的 IDE 例如 IntelliJ IDEA 已經可以自動為我們生成 equals 方法,還可以選擇是否允許子類判斷,是否可為 null 等判斷,所以我們就不必手動編寫了,但是生成的結果也是符合上面的 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()) { // 不涉及繼承,問題 1 和 問題 2 前半的寫法
            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)) { // 涉及繼承,使得與子類之間也可以判斷,問題 2 后半的寫法
            return false;
        }

        Person person = (Person) o;

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

scala 中編寫的方式大致相同,但是結合其語法,相比似乎又簡單又繁瑣。
簡單是指當沒有子類,或和子類判斷一定為 false 時(違反LSP),可以這樣寫:

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

繁瑣是指假如這時出現了一個子類 Student 且增加了一個域 sid,假如我們需要兩個類可相互判斷,則上述方法在判斷一個 Person 對象和一個 Student 對象時一定會返回 false

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

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

  override def equals(other: Any): Boolean = other match { // 問題 2 的寫法
    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 中的判斷更加靈活,比如可以限定不同子類與父類的判斷關系。

比如有一個 Person 的子類 Teacher,我們希望它只能和 Teacher 類進行判斷,與 PersonStudent 判斷都返回 false,該如何寫呢?一種錯誤的寫法如下:

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 違反了對稱性

正確的寫法應該是:

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 { // 問題 3 的寫法
    case that: Teacher =>
      super.equals(that) &&
        (that canEqual this) &&
        name == that.name &&
        age == that.age &&
        tid == that.tid
    case _ => false
  }
}

注意只覆蓋了 canEqual 方法也會違反對稱性。在 Java 中要實現相同的效果,則也需要編寫類似的 canEqual 方法,就留給讀者自己考慮了。

總之,在編寫單個類的 equals 方法時比較簡單,當涉及子類繼承時,就要多考慮一下了。

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

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68055.html

相關文章

  • 《Kotlin 極簡教程 》第4章 基本數據類型與類型系統

    摘要:本章我們來學習一下的基本數據類型與類型系統。字符串就是一個抽象數據類型。如果程序語言的語法中含有類型標記,就稱該語言是顯式類型化的,否則就稱為隱式類型化的。但是,可以把中對應的這幾種基本數據類型,理解為的基本類型的裝箱類。 第4章 基本數據類型與類型系統 《Kotlin極簡教程》正式上架: 點擊這里 > 去京東商城購買閱讀 點擊這里 > 去天貓商城購買閱讀 非常感謝您親愛的讀...

    MoAir 評論0 收藏0
  • Scala類型推導

    摘要:提供了類型推導來解決這個問題。函數式語言里比較經典的類型推導的方法是,并且它是在里首先使用的。的類型推導有一點點不同,不過思想上是一致的推導所有的約束條件,然后統一到一個類型上。而推導器是所有類型推導器的基礎。 Scala類型推導 之劍 2016.5.1 00:38:12 類型系統 什么是靜態類型?為什么它們很有用? 根據Picrce的說法:類型系統是一個可以根據代碼段計算出來的值對...

    SQC 評論0 收藏0
  • Kotlin框架巡禮

    摘要:框架官方支持的框架,風格頗為類似,并且充分發揮了的強類型優勢。這是一個主要面向的框架,為提供了一些額外特性。依賴注入框架用法簡單,支持等特性。 首先要說明,Kotlin支持你所知道的所有Java框架和庫,包括但不限于Spring全家桶、Guice、Hibernate、MyBatis、Jackson等,甚至有人在用Kotlin寫Spark大數據程序,因此Kotlin不需要專門的框架。因此...

    _Suqin 評論0 收藏0
  • Start Using Java Lambda Expressions(轉載)

    摘要:原文 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 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<