Java ==,equals()與hashcode()的使用
==,equals()與hashcode()
"=="
在講解之前,我們是怎么接觸到==
的,我們在作比較時經(jīng)常用到 ==
, 這個符號常用作基本類的數(shù)據(jù)。
==
運算符通常用于比較基本數(shù)據(jù)類型(如int、long、double等)和枚舉類型的值是否相等,而對于對象類型,==
運算符用于比較它們的引用是否相等,即它們是否指向同一個對象。
思考一個問題,為什么我們一般不使用==來比較對象,如果兩個對象的引用相同,即它們指向同一個對象,那么使用==
運算符比較它們的引用會返回true,因為它們確實指向同一個對象。在這種情況下,兩個對象的內(nèi)容自然是相同的,因為它們是同一個對象。
那為啥我們不直接使用==
去比較對象, 而要麻煩的使用其它的辦法,
因為: 我們比較對象不是想看它的引用是否相同,而是里面的屬性是否相同
在這種情況下,使用==
運算符比較兩個對象的引用并不能判斷它們的內(nèi)容是否相同,因為兩個不同的對象可能具有相同的屬性值,但它們的引用不同。因此,在比較對象是否相同時,應(yīng)該根據(jù)對象的語義來實現(xiàn)equals()
方法,而不是使用==
運算符。
public class Main { public static void main(String[] args) { int a = 5; int b = 5; int c = 6; System.out.println(a==b); // true System.out.println(a==c); // false Person p1 = new Person("hhh", 15); Person p2 = new Person("hhh", 15); // 屬性相同,但引用不同。按照常理應(yīng)該被認作是相同的。實際卻是不同的 System.out.println(p1 == p2); // false } } class Person{ String name; Integer age; Person(String name, Integer age){ this.age = age; this.name = name; } }
equals()方法
equals()
方法是Object
類中的方法,它僅僅是地址的比較,因此只能比較兩個類是否是同一個類,而不能比較屬性是否相同,因此,我們比較對象一般都會重寫equals()
方法
public class Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } // getters and setters @Override public boolean equals(Object obj) { return (this == obj); } }
如果一個類的屬性包含基本數(shù)據(jù)類型和引用數(shù)據(jù)類型,那么這些屬性值相同,但它們的引用地址也不一定相同。此時,必須重寫equals()
方法,根據(jù)對象的語義來進行比較,才能得到正確的結(jié)果。
列表中的使用
在Java中,列表類(如List
)通常用來存儲一組對象,當(dāng)我們需要在列表中查找某個對象時,通常需要調(diào)用列表的contains()
方法或indexOf()
方法。這些方法會使用對象的equals()
方法來比較對象是否相等。
它是通過比較對象的屬性值從而去列表中查找。
public class Main { public static void main(String[] args) { List<String> list = List.of("A", "B", "C"); // 下面的例子中即使對象的地址不同,但是屬性值相同,因此在列表中能查到 System.out.println(list.contains(new String("C"))); // true System.out.println(list.indexOf(new String("C"))); // 2 } }
在hash結(jié)構(gòu)的表中使用
map
是一種鍵值對的映射表,map
使用一個很大的數(shù)組來存儲value
,然后通過key
的hash
值來查找value
的索引
map
其實可以看作一個數(shù)組,key
的hashcode()
值可以作為數(shù)組的索引,然后根據(jù)索引去查找value
。
那究竟在什么地方使用equals()
呢?
當(dāng)我們輸入key
的時候,map
需要將傳入的key
與當(dāng)前數(shù)組中存入的key
相比較。
public class Main { public static void main(String[] args) { HashMap<String, String> map = new HashMap<>(); map.put(new String("sss"),"hhh"); map.put(new String("sss"), "aaa"); // map里只有一個數(shù)據(jù),因為String重寫了equals方法,所以key屬性值一樣的會被覆蓋 System.out.println(map.size()); HashMap<Person, String> map1 = new HashMap<>(); map1.put(new Person("xiao",15), "ok"); map1.put(new Person("xiao",15), "hao"); // map1里有兩個數(shù)據(jù),明明key是一樣的,卻沒有覆蓋 System.out.println(map1.size()); } } class Person{ String name; int age; Person(String name, int age){ this.name = name; this.age = age; } }
- 添加重復(fù)的鍵值對:由于
Map
將不同的對象視為不同的鍵,如果我們使用相同類型的不同對象作為鍵,即使它們的屬性值相同,Map
也會將它們視為不同的鍵,從而導(dǎo)致添加重復(fù)的鍵值對。 - 無法查找鍵值對:由于
Map
將不同的對象視為不同的鍵,如果我們使用一個對象作為鍵添加了一個鍵值對,而后又使用另一個對象作為鍵查找該鍵值對,那么Map
會認為這兩個對象是不同的鍵,因此無法找到對應(yīng)的鍵值對。
因此,我們需要正確重寫equals()
方法。
hashcode()方法
HashMap
為什么能通過key
直接計算出value
存儲的索引。相同的key
對象(使用equals()
判斷時返回true
)必須要計算出相同的索引,否則,相同的key
每次取出的value
就不一定對。
map
是通過hashcode()
去尋找value
數(shù)組索引的,所以還需要為對象覆寫hashcode()
方法。
public class Main { public static void main(String[] args) { HashMap<String, String> map = new HashMap<>(); map.put(new String("sss"),"hhh"); map.put(new String("sss"), "aaa"); // map里只有一個數(shù)據(jù),因為String重寫了equals方法和hashcode方法,所以key屬性值一樣的會被覆蓋 System.out.println(map.size()); // 1 HashMap<Person, String> map1 = new HashMap<>(); Person p1 = new Person("xiao", 15); map1.put(p1, "ok"); Person p2 = new Person("xiao", 15); map1.put(p2, "hao"); // map現(xiàn)在也只有一個數(shù)據(jù)了,因為兩個相同屬性的對象被視作同一個 System.out.println(map1.size()); // 1 } } class Person{ String name; int age; Person(String name, int age){ this.name = name; this.age = age; } // 覆寫equals方法 @Override public boolean equals(Object o) { if (o instanceof Person p) { return this.name.equals(p.name) && this.age == p.age; } return false; } // 覆寫hashcode方法 @Override public int hashCode() { int h = 0; h = 31 * h + name.hashCode(); h = 31 * h + age; return h; } }
map
的put
方法里是用到了hash
值的,因此不正確重寫hash
值而正確重寫equals
方法是沒用的。
小節(jié)
比較基本數(shù)據(jù)類型或?qū)ο蟮刂酚?code>==, 比較對象地址使用Object
的equals
方法, 比較對象屬性值使用覆寫之后的equals()
.
對于list
集合數(shù)據(jù)類型,本質(zhì)是數(shù)組,當(dāng)存儲對象數(shù)據(jù)類型的值時,重寫equals方法
才能使用contains()
等需要使用equals
進行比較的方法。
對于hash table類型的數(shù)據(jù),必須覆寫equals與hashcode方法,才能正常工作。
到此這篇關(guān)于Java ==,equals()與hashcode()的使用的文章就介紹到這了,更多相關(guān)Java ==,equals()與hashcode()內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot3通過GraalVM生成exe執(zhí)行文件問題
文章介紹了如何安裝GraalVM和Visual Studio,并通過Spring Boot項目將Java應(yīng)用程序封裝成可執(zhí)行文件(.exe)2024-12-12SpringCloud使用集中配置組件Config規(guī)避信息泄露
項目應(yīng)用中,數(shù)據(jù)庫連接信息、Access-key、Secret-key等由于其及其敏感和特殊性,一旦泄露出去就很可能會使得應(yīng)用遭到黑客攻擊,例如數(shù)據(jù)庫賬號密碼泄露可能導(dǎo)致“拖庫”,甚至數(shù)據(jù)丟失。此等事件偶有發(fā)生,那么,在分布式微服務(wù)項目中,怎么避免這種情況呢2022-07-07使用SpringBoot+EasyExcel+Vue實現(xiàn)excel表格的導(dǎo)入和導(dǎo)出詳解
這篇文章主要介紹了使用SpringBoot+VUE+EasyExcel?整合導(dǎo)入導(dǎo)出數(shù)據(jù)的過程詳解,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08使用kotlin集成springboot開發(fā)的超詳細教程
目前大多數(shù)都在使用java集成 springboot進行開發(fā),本文演示僅僅將 java換成 kotlin,其他不變的情況下進行開發(fā),需要的朋友可以參考下2021-09-09IntelliJ IDEA 2018 最新激活碼(截止到2018年1月30日)
這篇文章主要介紹了IntelliJ IDEA 2018 最新激活碼(截止到2018年1月30日)的相關(guān)資料,需要的朋友可以參考下2018-01-01ZooKeeper入門教程三分布式鎖實現(xiàn)及完整運行源碼
本文是ZooKeeper入門系列教程,分布式鎖有多種實現(xiàn)方式,比如通過數(shù)據(jù)庫、redis都可實現(xiàn)。作為分布式協(xié)同工具ZooKeeper,當(dāng)然也有著標準的實現(xiàn)方式。本文介紹在zookeeper中如何實現(xiàn)排他鎖2022-01-01基于java SSM springboot實現(xiàn)抗疫物質(zhì)信息管理系統(tǒng)
這篇文章主要介紹了基于JAVA SSM springboot實現(xiàn)的抗疫物質(zhì)信息管理系統(tǒng),本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-08-08