1. 程式人生 > >Java中==、equals、hashcode的區別與重寫equals以及hashcode方法例項

Java中==、equals、hashcode的區別與重寫equals以及hashcode方法例項

  1、重寫equals方法例項   部分程式碼參考http://blog.csdn.net/wangloveall/article/details/7899948

  重寫equals方法的目的是判斷兩個物件的內容(內容可以有很多,比如同時比較姓名和年齡,同時相同的才是用一個物件)是否相同

如果不重寫equals,那麼比較的將是物件的引用是否指向同一塊記憶體地址,重寫之後目的是為了比較兩個物件的value值是否相等。特別指出利用equals比較八大包裝物件
(如int,float等)和String類(因為該類已重寫了equals和hashcode方法)物件時,預設比較的是值,在比較其它自定義物件時都是比較的引用地址。
package com.lk.C;

class User {
    private String name;
    private int age;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setName(String name) {  
        this.name = name;  
    }
    public String getName() {  
        
return name; } public boolean equals(Object obj) { if(this == obj) { return true; } if(null == obj) { return false; } if(this.getClass() != obj.getClass()) { return false; } User user
= (User) obj; if(this.name.equals(user.name)&&this.age == user.age) { return true; } return false; } } public class Test6 { public static void main(String[] args) { User userA = new User(); userA.setName("王明"); userA.setAge(10); User userB = new User(); userB.setName("王明"); userB.setAge(10); User userC = new User(); userC.setName("王亮"); userC.setAge(10); System.out.println("userA equals userB:" + userA.equals(userB)); System.out.println("userA equals userC:" + userA.equals(userC)); } }
userA equals userB:true
userA equals userC:false

  在Java中,問什麼說重寫了equals方法都要進而重寫Hashcode方法呢?

原因如下:當equals此方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCode 方法的常規協定,該協定宣告相等物件必須具有相等的雜湊碼。如下:
(1)當obj1.equals(obj2)為true時,obj1.hashCode() == obj2.hashCode()必須為true 
(2)當obj1.hashCode() == obj2.hashCode()為false時,obj1.equals(obj2)必須為false

hashcode是用於雜湊資料的快速存取,如利用HashSet/HashMap/Hashtable類來儲存資料時,都是根據儲存物件的hashcode值來進行判斷是否相同的。

這樣如果我們對一個物件重寫了euqals,意思是隻要物件的成員變數值都相等那麼euqals就等於true,但不重寫hashcode,那麼我們再new一個新的物件,當原物件.equals(新物件)等於true時,兩者的hashcode卻是不一樣的,由此將產生了理解的不一致。

  2、看看下面的三段程式

package com.lk.C;

public class Test7 {
    public static void main(String[] args) {
        int a = 10;
        int b = 10;
        System.out.print("基本型別a==b:");
        System.out.println(a == b);
        System.out.println("-----");
        
        String s1 = "abc";
        String s2 = "abc";
        System.out.print("String型別是s1==s2:");
        System.out.println(s1 == s2);
        System.out.println("-----");
        
        String s3 = new String("abc");
        String s4 = new String("abc");//可以看出==比較的是棧的地址是否相同
        System.out.print("String型別用new String()是s1==s2:");
        System.out.println(s3 == s4);
        System.out.println(s1 == s3);
        System.out.println("-----");
        
        Integer i1 = 1;
        Integer i2 = 1;
        System.out.print("包裝型別是i1==i2:");
        System.out.println(i1 == i2);
        System.out.println("-----");
        
        Integer i3 = 128;
        Integer i4 = 128;//此時輸出false是因為Integer在-128-127之間會快取,超出這個範圍就不會快取了
        System.out.print("包裝型別是i3==i4:");
        System.out.println(i3 == i4);
        System.out.println("-----");
        
        Integer i5 = new Integer("1");
        Integer i6 = new Integer("1");
        System.out.print("包裝型別用new Integer()是i5==i6:");
        System.out.println(i5 == i6);//用new Integer()多少都不會快取
        System.out.println("-----");
        
        A a1 = new A(1);
        A a2 = new A(1);
        A a3 = a2;
        System.out.print("普通引用型別a1 == a2:");
        System.out.println(a1 == a2);
        System.out.println(a2 == a3);//物件賦給新物件連地址都是相同的
        System.out.println("-----");
    }
}

class A{
    int i;
    public A(int i){
        this.i = i;
    }
}
基本型別a==b:true
-----
String型別是s1==s2:true
-----
String型別用new String()是s1==s2:false
false
-----
包裝型別是i1==i2:true
-----
包裝型別是i3==i4:false
-----
包裝型別用new Integer()是i5==i6:false
-----
普通引用型別a1 == a2:false
true
-----
package com.lk.C;

public class Test8 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("基本型別沒有equals方法");
        System.out.println("-----");
        
        String s1 = "abc";
        String s2 = "abc";
        System.out.print("String型別的equals方法:");
        System.out.println(s1.equals(s2));
        System.out.println("-----");
        
        String s3 = new String("abc");
        String s4 = new String("abc");//可以看出比較equals方法比較的是堆裡的值是否相同
        System.out.print("String型別的new String()的equals方法:");
        System.out.println(s3.equals(s4));
        System.out.println("-----");
        
        System.out.print("String用==賦值和用new String()賦值的比較:");
        System.out.println(s1.equals(s3));
        System.out.println("-----");
        
        Integer i1 = 1;
        Integer i2 = 1;
        System.out.print("包裝類的equals方法:");
        System.out.println(i1.equals(i2));
        System.out.println("-----");
        
        Integer i3 = new Integer(1);
        Integer i4 = new Integer(1);
        System.out.print("包裝類的new Integer()用equals方法:");
        System.out.println(i3.equals(i4));
        System.out.println("-----");
        
        System.out.print("Integer用==賦值和用new Integer()賦值的比較:");
        System.out.println(i1.equals(i3));
        System.out.println("-----");
    }

}
基本型別沒有equals方法
-----
String型別的equals方法:true
-----
String型別的new String()的equals方法:true
-----
String用==賦值和用new String()賦值的比較:true
-----
包裝類的equals方法:true
-----
包裝類的new Integer()用equals方法:true
-----
Integer用==賦值和用new Integer()賦值的比較:true
-----
package com.lk.C;

public class Test9 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Student s1 = new Student("阿坤",21);
        Student s2 = new Student("阿坤",21);
        Student s3 = new Student();
        Student s4 = new Student();
        Student s5 = s1;
        System.out.print("普通類物件的==非預設構造:");
        System.out.println(s1 == s2);
        System.out.println(s1 == s5);
        System.out.println("-----");
        
        System.out.print("普通類物件的equals非預設構造:");
        System.out.println(s1.equals(s2));
        System.out.println(s1.equals(s5));
        System.out.println("-----");
        
        System.out.print("普通類物件的==預設構造:");
        System.out.println(s3 == s4);
        System.out.println("-----");
        
        System.out.print("普通類物件的equals預設構造:");
        System.out.println(s3.equals(s4));
        System.out.println("-----");
        
        System.out.print("對普通物件的屬性進行比較equals:");
        System.out.println(s1.name.equals(s2.name));
        System.out.print("對普通物件的屬性進行比較==:");
        System.out.println(s1.name == s2.name);
    }

}
class Student{
    public String name;
    public int age;
    public Student(){
        
    }
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
    public void test(){
        System.out.println(this.name);
        System.out.println(this.age);
    }
}
普通類物件的==非預設構造:false
true
-----
普通類物件的equals非預設構造:false
true
-----
普通類物件的==預設構造:false
-----
普通類物件的equals預設構造:false
-----
對普通物件的屬性進行比較equals:true
對普通物件的屬性進行比較==:true

  從以上的三個程式可以看出:

1)對於==:在簡單型別中(int等),這能使用該方法進行比較,這種型別沒有equals方法,int的值是存在棧中的,==比較的是棧的內容是否相同。在String型別中,比較特殊,用String=“”;這種進行賦值時,兩個相同的值用==比較也是相同的。但是用new String(),賦值就不相同。說明String=“”時,java會檢查在堆中是否由相同的值,如果有,把新物件的地址也同老物件的地址賦為相同,因此==比較會相同。但是new String()開闢的就是兩個棧,因此用==比較不會相同。對於包裝類,如Integer=“”;時,在-128-127會有快取,請看上面程式。其他的情況與String類似。

2)對於equals:當時String型別或者是包裝類,如Integer時,比較的就是堆中的值,Integer也無快取之說。對於普通類,equals比較的記憶體的首地址,這時候和==是一樣的,即比較兩邊指向的是不是同一個物件。詳細請見程式三。

以上程式都是親自測試過。希望能對大家有幫助。

以下是一些在百度中找到的說法:http://zhidao.baidu.com/link?url=AMYxGo3NunWY7irH5XLPlHUa0ywvyqgYEAdDUMKJlQvklm686MC_D7ZjT3dX9BmuZWXXjWRV2QHelGJ8GzAxBK

java中,
(1)對於字串變數來說,equal比較的兩邊物件的內容,所以內容相同返回的是true。
至於你沒問到的“==”,比較的是記憶體中的首地址,所以如果不是同一個物件,“==”不會返回true 而是false。
舉個簡單的例子,
String s1="abc", s2="abc";
String s3 =new String("abc");
String s4=new String("abc");
s1==s2 //true,
s1.equals(s2) //true,
s3.equals(s3) //true,equal比較的是內容
s3==s4//false,==比較的是首地址,所以是false
(2)對於非字串變數,equals比較的記憶體的首地址,這時候和==是一樣的,即比較兩邊指向的是不是同一個物件,
即
Sample sa1 = new Sample();
Sample sa2 = new Sample();
sa1.equals(sa2) //false,因為不是同一物件 
注意,如果加上
sa1=sa2;
那麼
sa1.equals(sa2) //true

相關推薦

Java==equalshashcode區別重寫equals以及hashcode方法例項

  1、重寫equals方法例項   部分程式碼參考http://blog.csdn.net/wangloveall/article/details/7899948   重寫equals方法的目的是判斷兩個物件的內容(內容可以有很多,比如同時比較姓名和年齡,同時相同的才是用一個物件)是否相同 如果不重寫e

javalist和set的區別聯絡

此文章是看別的大牛整理之後,自己學習進行消化後,對子自己的理解和得到的內容的一個總結。       介面Collection       Collection是java.util下的一個介面,它繼承的類是Iterable<E>。它是關於集合方面的一個跟介面,也就

Javaawt和swing的區別聯絡

AWT和Swing都是java中的包。 AWT(Abstract Window Toolkit):抽象視窗工具包,早期編寫圖形介面應用程式的包。 Swing :為解決 AWT 存在的問題而新開發的圖形介面包。Swing是對AWT的改良和擴充套件。     AWT和Swing的實現原理不同:  

java攔截器過濾器監聽器的區別

一、攔截器         interceptor:java裡的攔截器是動態攔截Action呼叫的物件。它提供了一種機制可以使開發者可以定義在一個action執行的前後執行的程式碼,也可以在一個action執行前阻止其執行,同時也提供了一種可以提取action中可重用部分的

淺談Java物件的==equalshashCode

目錄 運算子 == equals() String中的equals() Integer中的equals() Long中equals() hashCode() 運算子 == Java中的==是比較兩

Java String類StringBuilder類StringBuffer類 區別如何選擇

1. 概述:         1.1 String                   字串常量,但是它具有不可變性,就是一旦建立,對它進行的任何修改操作都會建立一個新的字串物件。         1.2 StringBuffer              

Java,StringStringBufferStringBuilder區別使用

一、簡介 在 Java 語言中,共有 8 個基本的資料型別,分別為:byte、short、int、long、float、double、boolean 和 char,其中 char 型別用於表示單個字元,例如 a、b、c 、A、B、C、& 這些大小寫

Javasuper關鍵字super關鍵字this關鍵字的區別

1 super關鍵字 1.1 super用於方法 1.1.1 用於構造方法   當子類呼叫父類無參構造時,super可寫可不寫,表示呼叫父類的無參構造!   當子類呼叫父類有參構造時,super(引數列表)必須要寫,要告訴編輯器呼叫的是哪個有參構造!  

java的StringStringBufferStringBuilder的區別

lin tr1 ffffff 線程安全 java api 安全 方法 大量數據 insert String、StringBuffer、StringBuilder都是java中的常用字符串類 ,下面來看看三者之間的異同。  一、可變與不可變:       String:字符串

PHPVC6VC9TSNTS版本的區別用法詳解

進行 系統資源 stc 詳解 ron 線程安全 info 啟動 win 1. VC6與VC9的區別: VC6版本是使用Visual Studio 6編譯器編譯的,如果你的PHP是用Apache來架設的,那你就選擇VC6版本。 VC9版本是使用Visual Studio 20

java的breakcontinuereturn區別

1、break: 可以用於for迴圈等迴圈體和開關語句switch case中; 用在迴圈中時,break是指跳出當前的迴圈體,如果是巢狀迴圈的話,只能跳出離break最近的for迴圈層;例如: public static void main(String[] args)

gccprintf/scanfprintf_P/scanf_P的區別用法

   從字面意思來看 printf/scanf是對RAM的操作,即把記憶體資料輸出/輸入到RAM。 printf_P/scanf_P是對ROM的操作,即把ROM資料輸出/輸入到ROM #include <avr/pgmspace.h> 這個標頭檔案用來訪問

Java的privateprotectedpublic和default的區別

(1)對於public修飾符,它具有最大的訪問許可權,可以訪問任何一個在CLASSPATH下的類、介面、異常等。它往往用於對外的情況,也就是物件或類對外的一種介面的形式。 (2)對於protected修飾符,它主要的作用就是用來保護子類的。它的含義在於子類可以用它修飾的成員,其他的不可以,它相當於傳遞給子類

Java的過載重寫和重構的區別

一、過載 過載(overloaded): 過載就是在同一個類中允許同時存在一個以上的同名方法,只要這些方法的引數個數或型別不同即可。 我們知道構造方法的名稱已經由類名決定,所以構造方法只有一個名稱,但如果希望以不同的方式來例項化物件,就需要使用多個構造方法來完成。由於這些構造方

Java的ObjectT(泛型)?區別

Object範圍非常廣,而T從一開始就會限定這個型別(包括它可以限定型別為Object)。 Object由於它是所有類的父類,所以會強制型別轉換,而T從一開始在編碼時(注意是在寫程式碼時)就限定了某種具體型別,所以它不用強制型別轉換。(之所以要強調在

java ,forfor-eachiterator 區別

java 中,for、for-each、iterator 區別: 無論是在陣列中還是在集合中,for-Each加強型for迴圈都是它們各自的普通for迴圈的一種“簡寫方式”,即兩者意思上是等價的,但前者方便簡單,建議多使用。 for-Each迴圈不能完全代替普通for迴圈,因為for-E

javaString類StringBuffer類StringBuilder類的區別(未完待續)

);}     public CharSequence subSequence(int beginIndex, int endIndex) {         return this.substring(beginIndex, endIndex);     }     /**      * 字串拼接    

Java-16】Java字串表示字串一些重要操作函式整數字串轉換

Java中有一個字串型別String,實際上確切說是有一個字串類,而類可以等價看作一個數據型別,所以我們就把String看成字串型別,String[]自然就是字串陣列,且對於每一個字串其都附帶很多方法,如字串切割等,具體看程式碼註釋解釋 package array; public class

java的DateCalendar的區別和聯絡

在學習java時,總會對日期的用法感到迷惑、但日期又是個大商業公司必須的,所以就認真的學習了一下java中的有關時間和日曆的類。 1、Date(import java.util.Date) 截止到jdk1.7該類中已經有很多方法遭到棄用,剩餘的方法不多。 Date date

Sqldecimalfloatdouble型別的區別用法

三者的區別介紹 float:浮點型,含位元組數為4,32bit,數值範圍為-3.4E38~3.4E38(7個有效位) double:雙精度實型,含位元組數為8,64bit數值範圍-1.7E308~1.7E308(15個有效位) decimal:數字型,128bit,不存