java-equals和==的比較規則和equals的重寫
2、==操作比較的是兩個變數的值是否相等,對於引用型變量表示的是兩個變數在堆中儲存的地址是否相同,即棧中的內容是否相同。
3、equals操作表示的兩個變數是否是對同一個物件的引用,即堆中的內容是否相同。
4、==比較的是2個物件的地址,而equals比較的是2個物件的內容,顯然,當equals為true時,==不一定為true。
==比較的是2個物件的地址,而equals比較的是2個物件的內容 !!!注意這句話的本質是因為常用的類覆蓋了object的equals方法使其由比較引用變為比較值
<span style="font-family:SimSun;font-size:12px;">public class EqualsTest { public static void main(String[] args) { Fish f1 = new Fish(1, "blue"); Fish f2 = new Fish(1, "blue"); System.out.println(f1 == f2); System.out.println(f1.equals(f2)); } } ——————執行結果為—————— false false</span>
由此可見 equals方法的本意是比較引用地址是否相等,指向同一個物件
而在JDK中,一些常用類覆蓋了Object中的equals方法,比較規則為:如果兩個物件的型別一致,且內容一致,返回true這些類有:java.io.file java.util.Data java.lang.string 包裝類(Intger Double)
<span style="font-family:SimSun;font-size:12px;">public class EqualsTest { public static void main(String[] args) { String s1=new String("sss"); String s2=new String("sss"); System.out.println(s1==s2); System.out.println(s1.equals(s2)); } } --------------------執行結果為---------- false true</span>
可見在 String中 equals方法被覆蓋,使其意義變為比較 內容是否相等
一、為什麼equals()方法要重寫?
判斷兩個物件在邏輯上是否相等,如根據類的成員變數來判斷兩個類的例項是否相等,而繼承Object中的equals方法只能判斷兩個引用變數是否是同一個物件。這樣我們往往需要重寫equals()方法。
我們向一個沒有重複物件的集合中新增元素時,集合中存放的往往是物件,我們需要先判斷集合中是否存在已知物件,這樣就必須重寫equals方法。
二、怎樣重寫equals()方法?
- 重寫equals方法的要求:
1.自反性:對於任何非空引用x,x.equals(x)應該返回true。
2.對稱性:對於任何引用x和y,如果x.equals(y)返回true,那麼y.equals(x)也應該返回true。
3.傳遞性:對於任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,那麼x.equals(z)也應該返回true。
4.一致性:如果x和y引用的物件沒有發生變化,那麼反覆呼叫x.equals(y)應該返回同樣的結果。
5.非空性:對於任意非空引用x,x.equals(null)應該返回false。
<span style="font-family:SimSun;font-size:12px;">public boolean equals(Object obj) {
if(this == obj)
return false;
if(obj == null)
return false;
if(getClass() != obj.getClass() )
return false;
MyClass other = (MyClass)obj;
if(str1 == null) {
if(obj.str1 != null) {
return false;
}
}else if (!str1.equals(other.str1) )
return false;
}
if(var1 != other.var1)
return false;
return true;
</span>
如果子類中增加了新特性,同時保留equals方法,這時比較複雜。
接下來我們通過例項來理解上面的約定。我們首先以一個簡單的非可變的二維點類作為開始:
public class Point{
private final int x;
private final int y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
public boolean equals(Object o){
if(!(o instanceof Point))
return false;
Point p = (Point)o;
return p.x == x && p.y == y;
}
}
假設你想要擴充套件這個類,為一個點增加顏色資訊:
public class ColorPoint extends Point{
private Color color;
public ColorPoint(int x, int y, Color color){
super(x, y);
this.color = color;
}
//override equasl()
public boolean equals(Object o){
if(!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint)o;
return super.equals(o) && cp.color==color;
}
}
我們重寫了equals方法,只有當實參是另一個有色點,並且具有同樣的位置和顏色的時候,它才返回true。可這個方法的問題在於,你在比較一個普通點和一個有色點,以及反過來的情形的時候,可能會得到不同的結果:
public static void main(String[] args){
Point p = new Point(1, 2);
ColorPoint cp = new ColorPoint(1, 2, Color.RED);
System.out.println(p.equals(cp));
System.out.println(cp.eqauls(p));
}
執行結果:
true
false
這樣的結果顯然違反了對稱性,你可以做這樣的嘗試來修正這個問題:讓ColorPoint.equals在進行“混合比較”的時候忽略顏色資訊:
public boolean equals(Object o){
if(!(o instanceof Point))
return false;
//如果o是一個普通點,就忽略顏色資訊
if(!(o instanceof ColorPoint))
return o.equals(this);
//如果o是一個有色點,就做完整的比較
ColorPoint cp = (ColorPoint)o;
return super.equals(o) && cp.color==color;
}
這種方法的結果會怎樣呢?讓我們先來測試一下:
public static void main(String[] args){
ColorPoint p1 = new ColorPoint(1, 2, Color.RED);
Point p2 = new Point(1, 2);
ColorPoint p3 = new ColorPoint(1, 2, Color.BLUE);
System.out.println(p1.equals(p2));
System.out.println(p2.equals(p1));
System.out.println(p2.equals(p3));
System.out.println(p1.eqauls(p3));
}
執行結果:
true
true
true
false
這種方法確實提供了對稱性,但是卻犧牲了傳遞性(按照約定,p1.equals(p2)和p2.eqauals(p3)都返回true,p1.equals(p3)也應返回true)。要怎麼解決呢?
事實上,這是面嚮物件語言中關於等價關係的一個基本問題。要想在擴充套件一個可例項化的類的同時,既要增加新的特徵,同時還要保留equals約定,沒有一個簡單的辦法可以做到這一點。新的解決辦法就是不再讓ColorPoint擴充套件Point,而是在ColorPoint中加入一個私有的Point域,以及一個公有的檢視(view)方法:
public class ColorPoint{
private Point point;
private Color color;
public ColorPoint(int x, int y, Color color){
point = new Point(x, y);
this.color = color;
}
//返回一個與該有色點在同一位置上的普通Point物件
public Point asPoint(){
return point;
}
public boolean equals(Object o){
if(o == this)
return true;
if(!(o instanceof ColorPoint))
return false;
ColorPoint cp = (ColorPoint)o;
return cp.point.equals(point)&&
cp.color.equals(color);
}
}
還有另外一個解決的辦法就是把Point設計成一個抽象的類(abstract class),這樣你就可以在該抽象類的子類中增加新的特徵,而不會違反equals約定。因為抽象類無法建立類的例項,那麼前面所述的種種問題都不會發生。
重寫equals方法的要點:
1. 使用==操作符檢查“實參是否為指向物件的一個引用”。
2.判斷實參是否為null
3. 使用instanceof操作符檢查“實參是否為正確的型別”。
4. 把實參轉換到正確的型別。
5. 對於該類中每一個“關鍵”域,檢查實參中的域與當前物件中對應的域值是否匹
配。對於既不是float也不是double型別的基本型別的域,可以使用==操作符
進行比較;對於物件引用型別的域,可以遞迴地呼叫所引用的物件的equals方法;
對於float型別的域,先使用Float.floatToIntBits轉換成int型別的值,
然後使用==操作符比較int型別的值;對於double型別的域,先使用
Double.doubleToLongBits轉換成long型別的值,然後使用==操作符比較
long型別的值。
6. 當你編寫完成了equals方法之後,應該問自己三個問題:它是否是對稱的、傳
遞的、一致的?(其他兩個特性通常會自行滿足)如果答案是否定的,那麼請找到
這些特性未能滿足的原因,再修改equals方法的程式碼。
相關推薦
java-equals和==的比較規則和equals的重寫
1、java中equals和==的區別 值型別是儲存在記憶體中的堆疊(簡稱棧),而引用型別的變數在棧中僅僅是儲存引用型別變數的地址,而其本身則儲存在堆中。 2、==操作比較的是兩個變數的值是否相等,對
java 中字串比較用=和equals區別
=:是比較兩個字串引用的地址是否相同,即是否指向同一個物件 equals方法:則比較字串的內容是否相同。 例如String a = "abc"; String b = "abc"; a == b返回true,a.equals(b)同樣返回true,這是為什
java中Bigdecimal比較大小和加減乘除
BigDecimal bignum1 = new BigDecimal("10"); BigDecimal bignum2 = new BigDecimal("5"); BigDecimal bignum3 = null; //加法 bignum3 = bignum1.add(bignum2);
Mysql系列(三)—— Mysql字符集和比較規則
二、檢視命令 檢視支援的字符集命令是:SHOW (CHARACTER SET|CHARSET) [LIKE 匹配的模式],CHARACTER SET|CHARSET同意,兩者都可以用。 檢視支援的比較規則命令是:SHOW COLLATION [LIKE 匹配的模式]。 注意,比較規則的命名方式有一定規律,一
Java之hashCode的作用和equals方法的重構規則
ide return 一點 eset log 什麽 bsp amp person 這個是博主對hashcode的初步理解,以後加深了會再來更新: 1、hashcode是什麽? hashcode是對象的散列碼,不同的對象幾乎不一樣,說幾乎是因為還是可以一樣的。 特點:每一個對
Java中字串比較方法equals()和equalsIgnoreCase()的區別
1. equals() equals( )是比較兩個字串是否相等,它的一般表示式如下: /** * Compares this string to the specified object. The result is {@code * true} if and o
學習筆記-JAVA-考點10-什麼情況下需要重寫equals和hashcode()兩個方法?
一、什麼情況下需要重寫equals和hashcode()兩個方法? 1、加入到hashset中的自定義類的物件,為確保他們不重複,需要對他們的類重寫equals()和hashcode()的方法。 如果不重寫equals,相同內容不同引用的物件會被當做不同的物件被加入到has
【JAVA學習】java中==、equals()、hashCode()都和物件的比較有關,在java中這三者各有什麼用處呢,即java中為什麼需要設計這三種物件的比較方法呢?
關於hashCode() 為什麼會設計hashCode()方法? hashCode()方法返回的就是一個數值,我們稱之為hashCode吧。從方法的名稱上就可以看出,其目的是生成一個hash碼。hash碼的主要用途就是在對物件進行雜湊的時候作為key輸入,據此很容易推斷出,我們需要每個物件的ha
Java比較String ==和equals() 解析
先看一個例子 equals() 比較String public class TestString { public static void main(String[] args) { String strOne = "testSt
從Java記憶體分配來看equals和==比較
剛開始學Java的時候,遇到equals比較和==比較有時候結果總是讓人驚訝,如果是以前沒有接觸過程式設計,不明白記憶體分配,每次都是稀裡糊塗的記住一些結果。這種是true那種是false,但
java課堂筆記------toString方法和equals方法
引用類型 logs obj blog () str pre ava 當我 * 重寫toString方法 * 當我們需要使用當前類的toString方法時,通常我們 * 就需要重寫該方法。具體返回字符串的格式沒有嚴格 * 要求,可
==和equals的比較
col str 新的 als 一個 bsp println span static 字符串只要new,就會產生一個新的地址 == :比較的是地址 str1,str2存儲在常量池中,內存優化,是同一個字符串 equals :比較的是內容,只要內容一樣結果就為true
java中正確使用hashCode和equals方法
Java 中正確使用 hashCode 和 equals 方法 轉載自:[開源中國社](http://www.oschina.net/question/82993_75533) 在這篇文章中,我將告訴大家我對hashCo
Java中整型數值==和equals的處理
前言: equals 比較內容, == 比較地址。 PS. equals在Object類中,作用和==完全是一樣的,都是對物件地址的比較,不是比較值。 在String類中,equals被重寫成了字串的具體值的比較,而不再是地址比較。 ==: 1)基本型別之間
java中equals()的用法以及和“==”的區別
== 的作用: 基本型別:比較的就是值是否相同 引用型別:比較的就是地址值是否相同 equals 的作用: 引用型別:預設情況下,比較的是地址值。 注:不過,我們可以根據情況自己重寫該方法。一般重寫都是自動生成,比較物件的成員變數值是否相同 public class Stri
Java 的equals()方法 和 == 的區別和聯絡
淺談Java中的equals和== 在初學Java時,可能會經常碰到下面的程式碼: String str1 = new String("hello"); String str2 = new String("hello"); System.out.print
java中==和eqauls()的區別,equals()和`hashcode的區別
==是運算子,用於比較兩個變數是否相等,而equals是Object類的方法,用於比較兩個物件是否相等。預設Object類的equals方法是比較兩個物件的地址,此時和==的結果一樣。換句話說:基本型別比較用==,比較的是他們的值。預設下,物件用==比較時,比較的是記憶體地址,如果需要比較物
String型別中 "=="和"equals"比較的差別
String型別中 "=="和"equals"比較的差別 先說明一下String型別的變數的建立方式 在建立新的String型別的變數時,首先會在緩衝區查詢是否有這個產量對應的物件,有就直接將找到的物件的地址賦給新建立的變數,沒有就重新建立一個物件,然後賦給新建立的變數 String
String中==和equals分別比較的是什麼?
首先先了解一下java中的==和equals分別比較的是什麼? 對於基本的資料型別來說:==比較的是兩個基本型別的值。 對於複合資料型別來說:==和equals比較的都是物件在記憶體中存放地址(確切的 說是堆記憶體地址)。
基本資料型別和String等對equals重寫了,其他的equals未重寫的例子
package test; public class Test1 { public static void main(String[] arg0) { Value v1 = new Val