一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Guava學(xué)習(xí)筆記:復(fù)寫的Object常用方法

 賈朋亮博客 2015-06-03
在Java中Object類是所有類的父類,其中有幾個需要override的方法比如equals,hashCode和toString等方法。 每次寫這幾個方法都要做很多重復(fù)性的判斷, 很多類庫提供了覆寫這幾個方法的工具類, Guava也提供了類似的方式。下面我們來看看Guava中這幾個方法簡單使用。

  equals方法:

  equals是一個經(jīng)常需要覆寫的方法, 可以查看Object的equals方法注釋, 對equals有幾個性質(zhì)的要求:
    1. 自反性reflexive:任何非空引用x,x.equals(x)返回為true;
    2. 對稱性symmetric:任何非空引用x和y,x.equals(y)返回true當(dāng)且僅當(dāng)y.equals(x)返回true;
    3. 傳遞性transitive:任何非空引用x和y,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)返回true;
    4. 一致性consistent:兩個非空引用x和y,x.equals(y)的多次調(diào)用應(yīng)該保持一致的結(jié)果,(前提條件是在多次比較之間沒有修改x和y用于比較的相關(guān)信息);
    5. 對于所有非null的值x, x.equals(null)都要返回false。 (如果你要用null.equals(x)也可以,會報NullPointerException)。

  當(dāng)我們要覆寫的類中某些值可能為null的時候,就需要對null做很多判斷和分支處理。 使用Guava的Objects.equal方法可以避免這個問題, 使得equals的方法的覆寫變得更加容易, 而且可讀性強,簡潔優(yōu)雅。

復(fù)制代碼
import org.junit.Test;
import com.google.common.base.Objects;

public class ObjectTest {
    
    @Test
    public void equalTest() {
        System.out.println(Objects.equal("a", "a"));
        System.out.println(Objects.equal(null, "a")); 
        System.out.println(Objects.equal("a", null)); 
        System.out.println(Objects.equal(null, null));
    }
    
    @Test
    public void equalPersonTest() {
        System.out.println(Objects.equal(new Person("peida",23), new Person("peida",23)));
        Person person=new Person("peida",23);
        System.out.println(Objects.equal(person,person));
    }
}

class Person {
    public String name;
    public int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
復(fù)制代碼

  運行輸出:

復(fù)制代碼
true
false
false
true
false
true
復(fù)制代碼

  hashCode方法:

  當(dāng)覆寫(override)了equals()方法之后,必須也覆寫hashCode()方法,反之亦然。 這個方法返回一個整型值(hash code value),如果兩個對象被equals()方法判斷為相等,那么它們就應(yīng)該擁有同樣的hash code。Object類的hashCode()方法為不同的對象返回不同的值,Object類的hashCode值表示的是對象的地址。
  hashCode的一般性契約(需要滿足的條件)如下:
  1.在Java應(yīng)用的一次執(zhí)行過程中,如果對象用于equals比較的信息沒有被修改,那么同一個對象多次調(diào)用hashCode()方法應(yīng)該返回同一個整型值。應(yīng)用的多次執(zhí)行中,這個值不需要保持一致,即每次執(zhí)行都是保持著各自不同的值。
  2.如果equals()判斷兩個對象相等,那么它們的hashCode()方法應(yīng)該返回同樣的值。
   3.并沒有強制要求如果equals()判斷兩個對象不相等,那么它們的hashCode()方法就應(yīng)該返回不同的值。即,兩個對象用equals() 方法比較返回false,它們的hashCode可以相同也可以不同。但是,應(yīng)該意識到,為兩個不相等的對象產(chǎn)生兩個不同的hashCode可以改善哈希 表的性能。
  寫一個hashCode本來也不是很難,但是Guava提供給我們了一個更加簡單的方法 --Objects.hashCode(Object ...), 這是個可變參數(shù)的方法,參數(shù)列表可以是任意數(shù)量,所以可以像這樣使用Objects.hashCode(field1, field2, ..., fieldn)。非常方便和簡潔。

  

復(fù)制代碼
import org.junit.Test;
import com.google.common.base.Objects;

public class ObjectTest {    
    @Test
    public void hashcodeTest() {
        System.out.println(Objects.hashCode("a"));
        System.out.println(Objects.hashCode("a"));
        System.out.println(Objects.hashCode("a","b"));
        System.out.println(Objects.hashCode("b","a"));
        System.out.println(Objects.hashCode("a","b","c"));
        
        Person person=new Person("peida",23);
        System.out.println(Objects.hashCode(person));
        System.out.println(Objects.hashCode(person));
    }
}

class Person {
    public String name;
    public int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
復(fù)制代碼
復(fù)制代碼
128
4066
4096
126145
19313256
19313256
復(fù)制代碼

  toString()方法:

  因為每個類都直接或間接地繼承自O(shè)bject,因此每個類都有toString()方法。這個方法是用得最多的, 覆寫得最多, 一個好的toString方法對于調(diào)試來說是非常重要的, 但是寫起來確實很不爽。Guava也提供了toString()方法。

  

復(fù)制代碼
import org.junit.Test;
import com.google.common.base.Objects;

public class ObjectTest {
    
    @Test
    public void toStringTest() {
        System.out.println(Objects.toStringHelper(this).add("x", 1).toString());
        System.out.println(Objects.toStringHelper(Person.class).add("x", 1).toString());
        
        Person person=new Person("peida",23);
        String result = Objects.toStringHelper(Person.class)
        .add("name", person.name)
        .add("age", person.age).toString();      
        System.out.print(result);
    }
}

class Person {
    public String name;
    public int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

//============輸出===============
ObjectTest{x=1}
Person{x=1}
Person{name=peida, age=23}
復(fù)制代碼

  compare/compareTo方法:

  CompareTo:compareTo(Object o)方法是java.lang.Comparable<T>接口中的方法,當(dāng)需要對某個類的對象進行排序時,該類需要實現(xiàn) Comparable<T>接口的,必須重寫public int compareTo(T o)方法。java規(guī)定,若a,b是兩個對象,當(dāng)a.compareTo(b)>0時,則a大于b,a.compareTo(b)<0 時,a<b,即規(guī)定對象的比較大小的規(guī)則;
  compare: compare(Object o1,Object o2)方法是java.util.Comparator<T>接口的方法,compare方法內(nèi)主要靠定義的compareTo規(guī)定的對象大小關(guān)系規(guī)則來確定對象的大小。

  compareTo方法的通用約定與equals類似:將本對象與指定的對象停止比擬,如果本對象小于、等于、或大于指定對象,則分離返回正數(shù)、零、或正數(shù)。如果指定的對象類型無法與本對象停止比擬,則跑出ClassCastException。
  對稱性:實現(xiàn)者必須保證對全部的x和y都有sgn(x.compareTo(y)) == -sgn(y.compareTo(x))。這也暗示當(dāng)且僅當(dāng)y.compareTo(x)拋出異常時,x.compareTo(y)才拋出異常。
  傳遞性:實 現(xiàn)者必須保證比擬關(guān)系是可傳遞的,如果x.compareTo(y) > 0且y.compareTo(z) > 0,則x.compareTo(z) > 0。實現(xiàn)者必須保證x.compareTo(y)==0暗示著全部的z都有(x.compareTo(z)) == (y.compareTo(z))。
  雖不強制要求,但強烈建議(x.compareTo(y) == 0) == (x.equals(y))。一般來說,任何實現(xiàn)了Comparable的類如果違背了這個約定,都應(yīng)該明白說明。推薦這么說:“注意:本類擁有自然順序,但與equals不一致”。
  第一條指出,如果顛倒兩個比擬對象的比擬順序,就會發(fā)生以下情況:如果第一個對象小于第二個對象,則第二個對象必須大于第一個對象;如果第一個對象等于第二個對象,則第二個對象也必須等于第一個對象;如果第一個對象大于第二個對象,則第二個對象小于第一個對象。
  第二條指出,如果第一個對象大于第二個對象,第二個對象大于第三個對象,則第一個大于第三個。
  第三條指出,對于兩個相稱的對象,他們與其他任何對象比擬結(jié)果應(yīng)該雷同。
   這三條約定的一個結(jié)果是,compareTo方法的等同性測試必須與equals方法滿意雷同的約束條件:自反性、對稱性、傳遞性。所以也存在類同的約 束:不能在擴展一個可實例化的類并添加新的值組件時,同時保證compareTo的約定,除非你愿意放棄面向?qū)ο蟪橄蟮膬?yōu)勢。可以用與equals雷同的 規(guī)避措施:如果想在實現(xiàn)Comparable接口的類中增加一個值組件,就不要擴展它;應(yīng)該寫一個不相干的類,其中包括第一個類的實例。然后供給一個 view方法返回該實例。這樣你就可以再第二個類上實現(xiàn)任何compareTo方法,同時允許客戶在須要的時候?qū)⒌诙€類看成是第一個類的一個實例。
   compareTo約定的最后一段是一個強烈的建議而非真正的約定,即compareTo方法的等同性測試必須與equals方法的結(jié)果雷同。如果遵照 了這一條,則稱compareTo方法所施加的順序與equals一致;反之則稱為與equals不一致。當(dāng)然與equals不一致的compareTo 方法仍然是可以工作的,但是,如果一個有序集合包括了該類的元素,則這個集合可能就不能遵照響應(yīng)集合接口(Collection、Set、Map)的通用 約定。這是因為這些接口的通用約定是基于equals方法的,但是有序集合卻使用了compareTo而非equals來執(zhí)行。

  下面我們簡單自己實現(xiàn)一個類的compareTo方法:

復(fù)制代碼
import org.junit.Test;

public class ObjectTest {
    
    
    @Test
    public void compareTest(){
        Person person=new Person("peida",23);
        Person person1=new Person("aida",25);
        Person person2=new Person("aida",25);
        Person person3=new Person("aida",26);
        Person person4=new Person("peida",26);
        
        System.out.println(person.compareTo(person1));
        System.out.println(person1.compareTo(person2));
        System.out.println(person1.compareTo(person3));
        System.out.println(person.compareTo(person4));
        System.out.println(person4.compareTo(person));    
    }
}

class Person implements Comparable<Person>{
    public String name;
    public int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public int compareTo(Person other) {
        int cmpName = name.compareTo(other.name);
        if (cmpName != 0) {
            return cmpName;
        }
        if(age>other.age){
            return 1;
        }
        else if(age<other.age){
            return -1;
        }
        return 0;  
    }
}
復(fù)制代碼
復(fù)制代碼
//========輸出===========
15 0 -1 -1 1
復(fù)制代碼

  上面的compareTo方法,代碼看上去并不是十分優(yōu)雅,如果實體屬性很多,數(shù)據(jù)類型豐富,代碼可讀性將會很差。在guava里, 對所有原始類型都提供了比較的工具函數(shù)來避免這個麻煩. 比如對Integer, 可以用Ints.compare()。利用guava的原始類型的compare,我們對上面的方法做一個簡化,實現(xiàn)compare方法:

復(fù)制代碼
class PersonComparator implements Comparator<Person> {  
    @Override 
    public int compare(Person p1, Person p2) {  
      int result = p1.name.compareTo(p2.name);  
      if (result != 0) {  
        return result;  
      }  
      return Ints.compare(p1.age, p2.age);  
    }  
  }  
復(fù)制代碼

  上面的代碼看上去簡單了一點,但還是不那么優(yōu)雅簡單,對此, guava有一個相當(dāng)聰明的解決辦法, 提供了ComparisonChain:

復(fù)制代碼
class Student implements Comparable<Student>{
    public String name;
    public int age;
    public int score;    
    
    Student(String name, int age,int score) {
        this.name = name;
        this.age = age;
        this.score=score;
    }
    
    @Override
    public int compareTo(Student other) {
        return ComparisonChain.start()
        .compare(name, other.name)
        .compare(age, other.age)
        .compare(score, other.score, Ordering.natural().nullsLast())
        .result();
    }
}

class StudentComparator implements Comparator<Student> {  
    @Override public int compare(Student s1, Student s2) {  
      return ComparisonChain.start()  
          .compare(s1.name, s2.name)  
          .compare(s1.age, s2.age)  
          .compare(s1.score, s2.score)  
          .result();  
    }  
  }  
}
復(fù)制代碼

  ComparisonChain是一個lazy的比較過程, 當(dāng)比較結(jié)果為0的時候, 即相等的時候, 會繼續(xù)比較下去, 出現(xiàn)非0的情況, 就會忽略后面的比較。ComparisonChain實現(xiàn)的comparecompareTo在代碼可讀性和性能上都有很大的提高。

  下面來一個綜合應(yīng)用實例:

復(fù)制代碼
import java.util.Comparator;

import org.junit.Test;

import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Ordering;

public class ObjectTest {

    
    @Test
    public void StudentTest(){
        
        Student student=new Student("peida",23,80);
        Student student1=new Student("aida",23,36);
        Student student2=new Student("jerry",24,90);
        Student student3=new Student("peida",23,80);
        
        System.out.println("==========equals===========");
        System.out.println(student.equals(student2));
        System.out.println(student.equals(student1));
        System.out.println(student.equals(student3));
        
        System.out.println("==========hashCode===========");
        System.out.println(student.hashCode());
        System.out.println(student1.hashCode());
        System.out.println(student3.hashCode());
        System.out.println(student2.hashCode());
        
        System.out.println("==========toString===========");
        System.out.println(student.toString());
        System.out.println(student1.toString());
        System.out.println(student2.toString());
        System.out.println(student3.toString());
        
        System.out.println("==========compareTo===========");
        System.out.println(student.compareTo(student1));
        System.out.println(student.compareTo(student2));
        System.out.println(student2.compareTo(student1));
        System.out.println(student2.compareTo(student));
        
    }

}

class Student implements Comparable<Student>{
    public String name;
    public int age;
    public int score;
    
    
    Student(String name, int age,int score) {
        this.name = name;
        this.age = age;
        this.score=score;
    }
    
    @Override
    public int hashCode() {
        return Objects.hashCode(name, age);
    }
    
    
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Student) {
            Student that = (Student) obj;
            return Objects.equal(name, that.name)
                    && Objects.equal(age, that.age)
                    && Objects.equal(score, that.score);
        }
        return false;
    }
    
    @Override
    public String toString() {
        return Objects.toStringHelper(this)
                .addValue(name)
                .addValue(age)
                .addValue(score)
                .toString();
    }
    
    
    @Override
    public int compareTo(Student other) {
        return ComparisonChain.start()
        .compare(name, other.name)
        .compare(age, other.age)
        .compare(score, other.score, Ordering.natural().nullsLast())
        .result();
    }
}



class StudentComparator implements Comparator<Student> {  
    @Override public int compare(Student s1, Student s2) {  
      return ComparisonChain.start()  
          .compare(s1.name, s2.name)  
          .compare(s1.age, s2.age)  
          .compare(s1.score, s2.score)  
          .result();  
    }  
  }  

//=============運行輸出===========================
==========equals===========
false
false
true
==========hashCode===========
-991998617
92809683
-991998617
-1163491205
==========toString===========
Student{peida, 23, 80}
Student{aida, 23, 36}
Student{jerry, 24, 90}
Student{peida, 23, 80}
==========compareTo===========
1
1
1
-1
復(fù)制代碼

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    高清国产日韩欧美熟女| 欧美加勒比一区二区三区| 国产成人精品午夜福利av免费| 亚洲一级在线免费观看| 欧美人妻少妇精品久久性色 | 日本丁香婷婷欧美激情| 97精品人妻一区二区三区麻豆| 欧美精品亚洲精品日韩专区| 欧美日韩一区二区综合| 久久精品国产99精品亚洲| 亚洲中文字幕人妻av| 亚洲五月婷婷中文字幕| 日本深夜福利视频在线| 欧美日韩亚洲国产精品| 日本免费熟女一区二区三区| 国产极品粉嫩尤物一区二区| 国产精品福利一级久久| 一级片二级片欧美日韩| 夫妻性生活真人动作视频| 91久久精品中文内射| 东京不热免费观看日本| 激情中文字幕在线观看| 少妇人妻无一区二区三区| 高中女厕偷拍一区二区三区| 99久久免费看国产精品| 欧美国产精品区一区二区三区| 熟女高潮一区二区三区| 欧美日韩一级黄片免费观看| 色一情一乱一区二区三区码| 国产精品一区二区日韩新区| 在线一区二区免费的视频| 午夜久久精品福利视频| 亚洲精品中文字幕无限乱码| 丁香七月啪啪激情综合| 国产女性精品一区二区三区| 日本免费熟女一区二区三区| 99久久精品午夜一区| 日本午夜免费观看视频| 亚洲天堂精品1024| 亚洲国产精品久久网午夜| 国产日韩熟女中文字幕|