==,est égal à()与hashcode()
"=="
Avant d'expliquer, comment sommes-nous entrés en contact avec lui==
? Nous l'utilisons souvent pour faire des comparaisons ==
. Ce symbole est souvent utilisé comme donnée de la classe de base.
==
Les opérateurs sont généralement utilisés pour comparer l'égalité des valeurs des types de données de base (tels que int, long, double, etc.) et des types d'énumération, tandis que pour les types d'objets, les opérateurs sont utilisés pour comparer si leurs références sont égales, c'est-à-dire s'ils pointent vers le même ==
objet .
Pensez à une question, pourquoi n'utilisons-nous généralement pas == pour comparer des objets, si les références de deux objets sont les mêmes, c'est-à-dire qu'elles pointent vers le même objet, alors l'utilisation de l'opérateur pour comparer leurs références renverra vrai ==
, car ils pointent vers le même objet. Dans ce cas, le contenu des deux objets est naturellement le même, puisqu'il s'agit du même objet.
Alors pourquoi ne pas utiliser directement ==
pour comparer des objets, mais utiliser d'autres méthodes en difficulté,
Parce que : on compare des objets non pas pour voir si leurs références sont les mêmes, mais si les propriétés à l'intérieur sont les mêmes
Dans ce cas, l'utilisation ==
de l'opérateur pour comparer les références de deux objets n'indique pas si leur contenu est identique, car deux objets différents peuvent avoir la même valeur de propriété, mais leurs références sont différentes. Par conséquent, lors de la comparaison d'objets pour l'égalité, equals()
les méthodes doivent être implémentées en fonction de la sémantique des objets, plutôt qu'en utilisant ==
des opérateurs.
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);
// 属性相同,但引用不同。按照常理应该被认作是相同的。实际却是不同的
System.out.println(p1 == p2); // false
}
}
class Person{
String name;
Integer age;
Person(String name, Integer age){
this.age = age;
this.name = name;
}
}
méthode equals()
equals()
Une méthode est Object
une méthode dans une classe. Il s'agit uniquement d'une comparaison d'adresses, de sorte qu'il ne peut être comparé que si deux classes sont de la même classe, mais pas si les attributs sont identiques. Par conséquent, nous redéfinissons généralement les méthodes lorsque nous comparons des equals()
objets
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);
}
}
Si les attributs d'une classe contiennent des types de données de base et des types de données de référence, alors ces valeurs d'attributs sont les mêmes, mais leurs adresses de référence ne sont pas nécessairement les mêmes. À ce stade, la méthode doit être réécrite equals()
et comparée en fonction de la sémantique des objets afin d'obtenir le résultat correct.
列表中的使用
在Java中,列表类(如List
)通常用来存储一组对象,当我们需要在列表中查找某个对象时,通常需要调用列表的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结构的表中使用
map
是一种键值对的映射表,map
使用一个很大的数组来存储value
,然后通过key
的hash
值来查找value
的索引
map
其实可以看作一个数组,key
的hashcode()
值可以作为数组的索引,然后根据索引去查找value
。
那究竟在什么地方使用equals()
呢?
当我们输入key
的时候,map
需要将传入的key
与当前数组中存入的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里只有一个数据,因为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里有两个数据,明明key是一样的,却没有覆盖
System.out.println(map1.size());
}
}
class Person{
String name;
int age;
Person(String name, int age){
this.name = name;
this.age = age;
}
}
- 添加重复的键值对:由于
Map
将不同的对象视为不同的键,如果我们使用相同类型的不同对象作为键,即使它们的属性值相同,Map
也会将它们视为不同的键,从而导致添加重复的键值对。 - 无法查找键值对:由于
Map
将不同的对象视为不同的键,如果我们使用一个对象作为键添加了一个键值对,而后又使用另一个对象作为键查找该键值对,那么Map
会认为这两个对象是不同的键,因此无法找到对应的键值对。
因此,我们需要正确重写equals()
方法。
hashcode()方法
HashMap
为什么能通过key
直接计算出value
存储的索引。相同的key
对象(使用equals()
判断时返回true
)必须要计算出相同的索引,否则,相同的key
每次取出的value
就不一定对。
map
是通过hashcode()
去寻找value
数组索引的,所以还需要为对象覆写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里只有一个数据,因为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现在也只有一个数据了,因为两个相同属性的对象被视作同一个
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
方法是没用的。
小节
比较基本数据类型或对象地址用==
, 比较对象地址使用Object
的equals
方法, 比较对象属性值使用覆写之后的equals()
.
对于list
集合数据类型,本质是数组,当存储对象数据类型的值时,重写equals方法
才能使用contains()
等需要使用equals
进行比较的方法。
对于hash table类型的数据,必须覆写equals与hashcode方法,才能正常工作。