Object的equals()方法:
Object是所有类的基类,不是接口的基类。
1.使用List的contains()、indexOf()这些方法,集合中对象是需要实现equals()方法。
2.在Map的内部,对key做比较是通过equals()实现的,正确使用Map必须保证:作为key的对象必须正确覆写equals()方法
3.Set实际上相当于只存储key、不存储value的Map。最常用的Set实现类是HashSet,实际上,HashSet仅仅是对HashMap的一个简单封装。Set的元素和Map的key类似,都要正确实现equals()和hashCode()方法,否则该元素无法正确地放入Set。放入HashSet的元素与作为HashMap的key要求相同。
如何写equals方法
1.先确定实例“相等”的逻辑,即哪些字段相等,就认为实例相等;
2.用instanceof判断传入的待比较的Object是不是当前类型,如果是,继续比较,否则,返回false;
3.对引用类型用Objects.equals()比较,对基本类型直接用==比较。
注意:使用Objects.equals()比较两个引用类型是否相等的目的是省去了判断null的麻烦。两个引用类型都是null时它们也是相等的。
当equals()方法被override时,hashCode()也要被override
public class Person {
String firstName;
String lastName;
int age;
@Override
public boolean equals(Object o) {
if (o instanceof Person) {
Person p = (Person) o;
return Objects.equals(this.firstName, p.firstName)
&&Objects.equals(this.lastName, p.lastName)
&& this.age == p.age;
}
return false;
}
@Override
int hashCode() {
int h = 0;
h = 31 * h + firstName.hashCode();
h = 31 * h + lastName.hashCode();
h = 31 * h + age;
return h;
}
}
Object的hashCode的用处
hashcode存在每个对象的堆内存的头部,如果两个对象相等,则两个对象的hashCode()必须相等。如果两个对象不相等,则两个对象的hashCode()尽量不要相等。如果两个对象hashcode都不相等,那么可以判断两个对象不相等,如果两个对象hashcode相等可以继续通过equals方法进行进一步比较。
HashMap相同的key对象(使用equals()判断时返回true)必须要利用hashCode计算出相同的索引
对于hashmap的key如果两个对象相等,则两个对象的hashCode()必须相等
如果两个对象不相等,则两个对象的hashCode()尽量不要相等
equals()用到的用于比较的每一个字段,都必须在hashCode()中用于计算;equals()中没有使用到的字段,绝不可放在hashCode()中计算
如何写hashCode方法
int hashCode() {
return Objects.hash(firstName, lastName, age);
}
一种利用set的去重算法
package com.example.test1;
import java.util.*;
public class DeReprocess {
public static void main(String[] args) {
List<Message> received = new ArrayList();
received.add(new Message(1, "Hello!"));
received.add(new Message(2, "发工资了吗?"));
received.add(new Message(2, "发工资了吗?"));
received.add(new Message(3, "去哪吃饭?"));
received.add(new Message(3, "去哪吃饭?"));
received.add(new Message(4, "Bye"));
List<Message> displayMessages = process(received);
for (Message message : displayMessages) {
System.out.println(message.text);
}
}
static List<Message> process(List<Message> received) {
List<Message> messages = new ArrayList<>();
Set<Message> sets = new HashSet<>();
for (Message mess : received) {
if (sets.add(mess)) {// sets按照 Message中eauals()方法的sequence和text去重
messages.add(mess);
}
}
received = messages;
return received;
}
}
class Message {
public final int sequence;
public final String text;
public Message(int sequence, String text) {
this.sequence = sequence;
this.text = text;
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof Message) {
Message m = (Message) o;
boolean textEqualsFlag=false;
if(text==null&&m.text==null){
textEqualsFlag=true;
}
if(text!=null){
textEqualsFlag=text.equals(m.text);
}
if (textEqualsFlag && sequence == m.sequence) {
return true;
}
}
return false;
}
public int hashCode() {
return Objects.hash(sequence, text);
}
}
SortedMap保证遍历时以Key的顺序来进行排序。使用TreeMap时,放入的Key必须实现Comparable接口。String、Integer这些类已经实现了Comparable接口,因此可以直接作为Key使用。如果作为Key的class没有实现Comparable接口,那么,必须在创建TreeMap时同时指定一个自定义排序算法:
public class Main {
public static void main(String[] args) {
Map<Student, Integer> map = new TreeMap<>(new Comparator<Student>() {
public int compare(Student p1, Student p2) {
// 去掉注释,否则 System.out.println(map.get(new Student("Bob", 66)))为null
//if (p1.score == p2.score) {
// return 0;
//}
return p1.score > p2.score ? -1 : 1;
}
});
map.put(new Student("Tom", 77), 1);
map.put(new Student("Bob", 66), 2);
map.put(new Student("Lily", 99), 3);
for (Student key : map.keySet()) {
System.out.println(key);
}
System.out.println(map.get(new Student("Bob", 66))); // null?
}
}
class Student {
public String name;
public int score;
Student(String name, int score) {
this.name = name;
this.score = score;
}
public String toString() {
return String.format("{%s: score=%d}", name, score);
}
}