Sobes.tech
Middle

Պատմեք Java-ում hashCode և equals մեթոդների պայմանների մասին։

sobes.tech AI

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

Java-յի hashCode և equals մեթոդների պայմանագիրը սահմանում է նրանց փոխկապակցվածությունը և ապահովում է օբյեկտների ճիշտ վարքագիծը հեշ-թաբկային հավաքածուներում (օրինակ, HashSet, HashMap) օգտագործելիս:

Հիմնական կանոնները:

  1. Ռեֆլեկտիվություն: Ամեն մի ոչ-զրո հղումային արժեք x համար, x.equals(x) պետք է վերադարձնի true:
  2. Սիմետրիկություն: Ամեն մի ոչ-զրո հղումային արժեք x և y համար, x.equals(y) պետք է վերադարձնի true միայն այն դեպքում, երբ y.equals(x) նույնպես true է:
  3. Տրանզիտություն: Ամեն մի ոչ-զրո հղումային արժեք x, y և z համար, եթե x.equals(y) և y.equals(z) true են, ապա x.equals(z) նույնպես true է:
  4. Կոնսիստենտություն: Ամեն մի ոչ-զրո հղումային արժեք x և y համար, բազմակի x.equals(y) կանչերը նույն արդյունքը պետք է տալ, եթե x և y փոփոխական չեն փոխվել:
  5. Ոչ-զրո արժեք: Ամեն մի ոչ-զրո հղումային արժեք x համար, x.equals(null) պետք է վերադարձնի false:

Եվ հիմնական կանոնը, որը կապում է hashCode և equals:

  • Եթե երկու օբյեկտներ հավասար են equals(Object) մեթոդով, ապա նրանց hashCode() մեթոդը պետք է վերադարձնի նույն ամբողջ թիվը:
  • հակառակը չէ ճիշտ: եթե երկու օբյեկտների հեշ-կոդը նույնն է, դա չէ նշանակում, որ նրանք հավասար են:

Կոնտակտի արժեք:

Կոտրումը պայմանագրի կարող է հանգեցնել հավաքածուների սխալ աշխատանքի: Օրինակ, եթե երկու հավասար օբյեկտներ վերադարձնեն տարբեր հեշ-կոդեր, HashMap-ը կարող է դրանք տեղադրել տարբեր "խցիկներում" (buckets) և չի կարող գտնել մեկը մյուսի միջոցով, նույնիսկ եթե նրանք տրամաբանականորեն հավասար են:

Օրինակ ճիշտ իրականացում:

// Օրինակ կլաս, որը ճիշտ է `equals` և `hashCode`-ով
public final class Point {
    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Point point = (Point) o;
        return x == point.x && y == point.y;
    }

    @Override
    public int hashCode() {
        int result = 17; // Մոգական թիվ, սովորաբար պարզ
        result = 31 * result + x;
        result = 31 * result + y;
        return result;
    }

    // Գеттерներ (ոչ պարտադիր `equals`/`hashCode` համար)
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

Օգտագործում:

  • Ամեն ժամանակ վերանայեք երկու մեթոդները (equals և hashCode) միասին:
  • Հաշվարկելիս hashCode-ը օգտագործեք նույն դաշտերը, որոնք օգտագործվում են equals-ում:
  • Փորձեք ստեղծել "լավ" հեշ-ֆունկցիաներ, որոնք հավասարապես տարածում են հեշ-կոդերը, որպեսզի նվազեցնեն բախումները (երբ տարբեր օբյեկտներ ունեն նույն հեշ-կոդը) և բարելավեն հեշավորված հավաքածուների կատարողականությունը:
  • Պրիմիտիվների համար օգտագործեք նրանց արժեքները: Օբյեկտների համար կանչեք hashCode(): Մասիվների համար օգտագործեք Arrays-ի մեթոդները:

Java 7+-ում խորհուրդ է տրվում օգտագործել Objects.equals(Object a, Object b) և `Objects.hash(Object... values)``:

Օրինակ Objects-ի հետ:

// Օրինակ կլաս, որը `equals` և `hashCode`-ով օգտագործում է `Objects`
import java.util.Objects;

public final class PointWithObjects {
    private final int x;
    private final int y;

    public PointWithObjects(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PointWithObjects that = (PointWithObjects) o;
        return x == that.x && y == that.y; // Լոգիկան մնում է նույն
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y); // Հարմար մեթոդ հեշի հաշվարկի համար
    }
}