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中==、equals、hashcode的區別與重寫equals以及hashcode方法例項
1、重寫equals方法例項 部分程式碼參考http://blog.csdn.net/wangloveall/article/details/7899948 重寫equals方法的目的是判斷兩個物件的內容(內容可以有很多,比如同時比較姓名和年齡,同時相同的才是用一個物件)是否相同 如果不重寫e
java中list和set的區別與聯絡
此文章是看別的大牛整理之後,自己學習進行消化後,對子自己的理解和得到的內容的一個總結。 介面Collection Collection是java.util下的一個介面,它繼承的類是Iterable<E>。它是關於集合方面的一個跟介面,也就
Java中awt和swing的區別與聯絡
AWT和Swing都是java中的包。 AWT(Abstract Window Toolkit):抽象視窗工具包,早期編寫圖形介面應用程式的包。 Swing :為解決 AWT 存在的問題而新開發的圖形介面包。Swing是對AWT的改良和擴充套件。 AWT和Swing的實現原理不同:
java中攔截器、過濾器與監聽器的區別
一、攔截器 interceptor:java裡的攔截器是動態攔截Action呼叫的物件。它提供了一種機制可以使開發者可以定義在一個action執行的前後執行的程式碼,也可以在一個action執行前阻止其執行,同時也提供了一種可以提取action中可重用部分的
淺談Java中物件的==、equals和hashCode
目錄 運算子 == equals() String中的equals() Integer中的equals() Long中equals() hashCode() 運算子 == Java中的==是比較兩
Java中 String類、StringBuilder類、StringBuffer類 區別與如何選擇
1. 概述: 1.1 String 字串常量,但是它具有不可變性,就是一旦建立,對它進行的任何修改操作都會建立一個新的字串物件。 1.2 StringBuffer
Java中,String、StringBuffer、StringBuilder區別與使用
一、簡介 在 Java 語言中,共有 8 個基本的資料型別,分別為:byte、short、int、long、float、double、boolean 和 char,其中 char 型別用於表示單個字元,例如 a、b、c 、A、B、C、& 這些大小寫
Java中super關鍵字、super關鍵字與this關鍵字的區別
1 super關鍵字 1.1 super用於方法 1.1.1 用於構造方法 當子類呼叫父類無參構造時,super可寫可不寫,表示呼叫父類的無參構造! 當子類呼叫父類有參構造時,super(引數列表)必須要寫,要告訴編輯器呼叫的是哪個有參構造!
java中的String、StringBuffer、StringBuilder的區別
lin tr1 ffffff 線程安全 java api 安全 方法 大量數據 insert String、StringBuffer、StringBuilder都是java中的常用字符串類 ,下面來看看三者之間的異同。 一、可變與不可變: String:字符串
PHP中VC6、VC9、TS、NTS版本的區別與用法詳解
進行 系統資源 stc 詳解 ron 線程安全 info 啟動 win 1. VC6與VC9的區別: VC6版本是使用Visual Studio 6編譯器編譯的,如果你的PHP是用Apache來架設的,那你就選擇VC6版本。 VC9版本是使用Visual Studio 20
java中的break、continue、return區別
1、break: 可以用於for迴圈等迴圈體和開關語句switch case中; 用在迴圈中時,break是指跳出當前的迴圈體,如果是巢狀迴圈的話,只能跳出離break最近的for迴圈層;例如: public static void main(String[] args)
gcc中printf/scanf、printf_P/scanf_P的區別與用法
從字面意思來看 printf/scanf是對RAM的操作,即把記憶體資料輸出/輸入到RAM。 printf_P/scanf_P是對ROM的操作,即把ROM資料輸出/輸入到ROM #include <avr/pgmspace.h> 這個標頭檔案用來訪問
Java中的private、protected、public和default的區別
(1)對於public修飾符,它具有最大的訪問許可權,可以訪問任何一個在CLASSPATH下的類、介面、異常等。它往往用於對外的情況,也就是物件或類對外的一種介面的形式。 (2)對於protected修飾符,它主要的作用就是用來保護子類的。它的含義在於子類可以用它修飾的成員,其他的不可以,它相當於傳遞給子類
Java中的過載、重寫和重構的區別
一、過載 過載(overloaded): 過載就是在同一個類中允許同時存在一個以上的同名方法,只要這些方法的引數個數或型別不同即可。 我們知道構造方法的名稱已經由類名決定,所以構造方法只有一個名稱,但如果希望以不同的方式來例項化物件,就需要使用多個構造方法來完成。由於這些構造方
Java中的Object、T(泛型)、?區別
Object範圍非常廣,而T從一開始就會限定這個型別(包括它可以限定型別為Object)。 Object由於它是所有類的父類,所以會強制型別轉換,而T從一開始在編碼時(注意是在寫程式碼時)就限定了某種具體型別,所以它不用強制型別轉換。(之所以要強調在
java 中,for、for-each、iterator 區別
java 中,for、for-each、iterator 區別: 無論是在陣列中還是在集合中,for-Each加強型for迴圈都是它們各自的普通for迴圈的一種“簡寫方式”,即兩者意思上是等價的,但前者方便簡單,建議多使用。 for-Each迴圈不能完全代替普通for迴圈,因為for-E
java中String類、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中的Date、Calendar的區別和聯絡
在學習java時,總會對日期的用法感到迷惑、但日期又是個大商業公司必須的,所以就認真的學習了一下java中的有關時間和日曆的類。 1、Date(import java.util.Date) 截止到jdk1.7該類中已經有很多方法遭到棄用,剩餘的方法不多。 Date date
Sql中decimal、float、double型別的區別與用法
三者的區別介紹 float:浮點型,含位元組數為4,32bit,數值範圍為-3.4E38~3.4E38(7個有效位) double:雙精度實型,含位元組數為8,64bit數值範圍-1.7E308~1.7E308(15個有效位) decimal:數字型,128bit,不存