Sobes.tech
Middle

Ինչու է կարևոր Java-ում վերագրել equals և hashCode մեթոդները:

sobes.tech AI

Պատասխան AI-ից

equals և hashCode-ի վերանվանումը կարևոր է օբյեկտների ճիշտ աշխատանքի համար հավաքածուներում և համեմատության ժամանակ:

  1. Սիմետրիկություն: Եթե a.equals(b) վերադարձնում է true, ապա b.equals(a) նույնպես պետք է լինի true:
  2. Ռեֆլեկտիվություն: Ամեն մի ոչ զրոյական օբյեկտ a համար, a.equals(a) պետք է լինի true:
  3. Տրանզիտիվություն: Եթե a.equals(b) և b.equals(c) վերադարձնում են true, ապա a.equals(c) նույնպես պետք է լինի true:
  4. Կոնսիստենտություն: Շատ անգամ a.equals(b) կանչերը պետք է կայունորեն վերադարձնեն true կամ false, եթե equals-ում օգտագործված տեղեկությունները չեն փոխվել:

hashCode-ի համար:

  1. Կոնսիստենտություն: Եթե equals-ում օգտագործված տեղեկությունները չեն փոխվել, ապա hashCode-ի բազմակի կանչերը պետք է վերադարձնեն նույն ամբողջական թիվը:
  2. Կապ equals-ի հետ: Եթե երկու օբյեկտներ համընկնում են equals-ի համաձայն, ապա նրանց hashCode-ը պետք է լինի նույնը:
  3. Օպտիմալացում: Չի պահանջվում, որ եթե երկու օբյեկտներ չեն համընկնում equals-ի համաձայն, նրանց hashCode-ը տարբեր լինի, բայց տարբեր hashCode-ներ ստեղծելը կարող է բարելավել հեշ-թաբլետների կատարողականությունը:

Այս կանոնների խախտումը կարող է հանգեցնել անսպասելի վարքագծի, երբ օգտագործվում են HashSet, HashMap, ArrayList և այլ հավաքածուներ, որոնք հիմնված են այս մեթոդների ճիշտ իրականացման վրա՝ օբյեկտների հավասարության և տեղադրության ճիշտ որոշման համար:

Օրինակ՝

// Օրինակ՝ դաս առանց ճիշտ `equals` և `hashCode`
class PersonBroken {
    private String name;
    private int age;

    public PersonBroken(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // getter-ներ բաց թողնված՝ կարճության համար
}

// Օրինակ՝ դաս ճիշտ `equals` և `hashCode`-ով
class PersonCorrect {
    private String name;
    private int age;

    public PersonCorrect(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PersonCorrect that = (PersonCorrect) o;
        return age == that.age &&
               Objects.equals(name, that.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    // getter-ներ բաց թողնված՝ կարճության համար
}

// Օգտագործում հավաքածուում
List<PersonBroken> brokenList = new ArrayList<>();
brokenList.add(new PersonBroken("Alice", 30));
System.out.println(brokenList.contains(new PersonBroken("Alice", 30))); // Հավանաբար՝ false

List<PersonCorrect> correctList = new ArrayList<>();
correctList.add(new PersonCorrect("Alice", 30));
System.out.println(correctList.contains(new PersonCorrect("Alice", 30))); // Հավանաբար՝ true

Set<PersonBroken> brokenSet = new HashSet<>();
brokenSet.add(new PersonBroken("Bob", 25));
brokenSet.add(new PersonBroken("Bob", 25));
System.out.println(brokenSet.size()); // Հավանաբար՝ 2

Set<PersonCorrect> correctSet = new HashSet<>();
correctSet.add(new PersonCorrect("Bob", 25));
correctSet.add(new PersonCorrect("Bob", 25));
System.out.println(correctSet.size()); // Հավանաբար՝ 1

Օրինակ՝ PersonBroken-ի դեպքում, նույն դաշտերի արժեքներով օբյեկտները համարվում են տարբեր, քանի որ օգտագործվում են equals-ի դեֆոլտային (համեմատում է հղումները) և hashCode-ի (գեներացվում է օբյեկտի հասցեով) իրականացումները: PersonCorrect-ի դեպքում, վերագրած մեթոդները թույլ են տալիս հավաքածուներին ճիշտ որոշել օբյեկտների հավասարությունը նրանց պարունակության հիման վրա։