[Autorisation d'un article] ==, l'utilisation de equals() et hashcode()

==,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 Objectune 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,然后通过keyhash值来查找value的索引

map其实可以看作一个数组,keyhashcode()值可以作为数组的索引,然后根据索引去查找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;
    }
}
  1. 添加重复的键值对:由于Map将不同的对象视为不同的键,如果我们使用相同类型的不同对象作为键,即使它们的属性值相同,Map也会将它们视为不同的键,从而导致添加重复的键值对。
  2. 无法查找键值对:由于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;
    }
}

mapput方法里是用到了hash值的,因此不正确重写hash值而正确重写equals方法是没用的。

小节

比较基本数据类型或对象地址用==, 比较对象地址使用Objectequals方法, 比较对象属性值使用覆写之后的equals().

对于list集合数据类型,本质是数组,当存储对象数据类型的值时,重写equals方法才能使用contains()等需要使用equals进行比较的方法。

对于hash table类型的数据,必须覆写equals与hashcode方法,才能正常工作。

Guess you like

Origin juejin.im/post/7235118809605292087