關(guān)于“==”操作符
眾所周知,在Java中對(duì)于基本數(shù)據(jù)類型來(lái)說(shuō)“==”操作符用于比較兩個(gè)變量的值是否相等昵慌,而對(duì)于引用類型來(lái)說(shuō)“==”比較的是對(duì)象指向的引用是否一致假夺。舉個(gè)例子,先定義一個(gè)User類:
public class User{
private String name;
private int age;
public User(String name,int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
在測(cè)試類的main函數(shù)中添加如下代碼可以得到輸出:
User user1 = new User("abc",12);
User user2 = new User("abc",12);
User user3 = user1;
System.out.println(user1==user2);//輸出false斋攀,user1和user2指向兩個(gè)不同的引用
System.out.println(user1==user3);//輸出true已卷,user1的引用被傳遞給了user3
user3.setName("cde");//改變user3中的值
System.out.println(user1.getName());//輸出“cde”,user1與user3指向同一引用
System.out.println(user1 == user3);//輸出true淳蔼,由于user1與user3兩個(gè)對(duì)象具有相同的引用侧蘸,改變user3其實(shí)就是改變user1。
由此可得:當(dāng)用“=”把一個(gè)引用對(duì)象賦值給另外一個(gè)引用對(duì)象后鹉梨,此時(shí)使用“==”比較兩個(gè)對(duì)象返回true讳癌,兩個(gè)對(duì)象操作的是同一個(gè)引用,修改一個(gè)對(duì)象會(huì)影響另外一個(gè)對(duì)象存皂。
關(guān)于equals方法
equals方法存在于Object類中晌坤,所以Java所有類默認(rèn)都有這個(gè)方法,下面看看Object中equals方法是怎么實(shí)現(xiàn)的
public boolean equals(Object obj) {
return (this == obj);
}
從上面的代碼可以看出在Object中的equals方法是使用“==”符號(hào)比較兩個(gè)對(duì)象是否相同旦袋,所以把上一節(jié)代碼中的“==”換成equals后結(jié)果是一樣的骤菠。此時(shí)有人可能會(huì)有疑問(wèn),那為啥平時(shí)使用的String類型只要字符串一樣equals方法就返回true疤孕,那是因?yàn)镾tring類重寫了equals方法商乎。我們也可以重寫User類的equals方法代碼如下:
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj instanceof User){
User user = (User)obj;
if(this.name.equals(user.getName)&&this.age == user.getAge()){
return true;
}
}
return false;
}
main函數(shù)與輸出代碼如下:
User user1 = new User("abc",12);
User user2 = new User("abc",12);
User user3 = new User("cde",12);
System.out.println(user1.equals(user2));//輸出true,name和age都相等
System.out.println(user1.equals(user3));//輸出false祭阀,name不等鹉戚。
從結(jié)果來(lái)看實(shí)現(xiàn)了我們想要的,但是這里面還存在一個(gè)問(wèn)題专控,因?yàn)檫@個(gè)類在重寫了equals方法的同時(shí)卻沒(méi)有重寫hashCode方法抹凳,這會(huì)導(dǎo)致這個(gè)類無(wú)法與所有基于散列的集合類一起正常使用。讓我們看下面這個(gè)例子:
Map<User,String> map = new HashMap<>();
map.put(new User("xiaojian",12),"abc");
System.out.println(map.get(new User("xiaojian",12)));//輸出null踩官,并沒(méi)有輸出我們期望的結(jié)果“abc”
上面的結(jié)果是因?yàn)樯厦鎝ut與get的實(shí)例雖然相等,但是他們的hashCode卻不相等境输,HashMap在查詢時(shí)當(dāng)檢測(cè)到hashCode不一致時(shí)也不會(huì)檢驗(yàn)對(duì)象的一致性蔗牡。為了保證HashMap能正常工作嗅剖,我們重寫User類的hashCode方法如下:
public int hashCode(){
return 17;
}
這個(gè)時(shí)候上面那段代碼輸出“abc”辩越,得到我們期望的結(jié)果了,但這時(shí)別高興太早信粮,由于這里返回的固定值黔攒,所有User對(duì)象都具有一個(gè)相同的hashCode,這違反了hashCode的三大原則:
那么要怎么改呢?下面是修改的一些原則:
根據(jù)這個(gè)原則修改hashCode方法如下:
public int hashCode(){
int result = 17;
result = result *31+age;
result = result * 31 + name.hashCode
}