hashCode लागू करना
सही hash फ़ंक्शन लिखें
hashCode लागू करना, CoddyKit पर Java Academy का एक निःशुल्क पाठ है। यह 4 में से 3वाँ पाठ है। आप नीचे पूरा पाठ निःशुल्क पढ़ सकते हैं—फिर अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर के साथ ब्राउज़र में इसका व्यावहारिक अभ्यास कर सकते हैं। यह Java Academy सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। Java Academy पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
अच्छे hashCode के लक्ष्य
एक अच्छे hashCode() को:
- समान वस्तुओं के लिए समान मान लौटाना चाहिए (अनुबंध के अनुसार)।
- असमान वस्तुओं को कई अलग-अलग मानों में फैलाना चाहिए।
- इसकी गणना कम लागत वाली होनी चाहिए।
एक खराब hashCode, जो स्थिर मान लौटाता है, फिर भी अनुबंध पूरा करता है, लेकिन मानचित्र को धीमी श्रृंखलाबद्ध सूची में बदल देता है।
public class Main {
public static void main(String[] args) {
// Legal but terrible: every object collides
System.out.println("constant hashCode is legal but kills performance");
}
}सामान्य स्थिति के लिए Objects.hash
सबसे सरल सही तरीका है Objects.hash(field1, field2, ...)।
यह शून्य मानों को संभालता है और मानक एल्गोरिदम से फ़ील्ड को मिलाता है। equals में जिन समान फ़ील्ड की तुलना करते हैं, उन्हीं का उपयोग करें।
import java.util.Objects;
public class Main {
static class User {
final String name; final int age;
User(String name, int age) { this.name = name; this.age = age; }
@Override public int hashCode() { return Objects.hash(name, age); }
}
public static void main(String[] args) {
User a = new User("Ada", 36);
User b = new User("Ada", 36);
System.out.println(a.hashCode() == b.hashCode());
}
}पारंपरिक 31 गुणक
हाथ से लिखे गए hash के लिए मानक तरीका है कि चलते हुए परिणाम को 31 से गुणा किया जाए और हर फ़ील्ड का hash उसमें जोड़ा जाए।
31 एक विषम अभाज्य संख्या है, और 31 * x तथा (x << 5) - x समान हैं, इसलिए JVM इसे अनुकूलित कर सकता है।
public class Main {
static class User {
final String name; final int age;
User(String name, int age) { this.name = name; this.age = age; }
@Override public int hashCode() {
int result = 17;
result = 31 * result + (name == null ? 0 : name.hashCode());
result = 31 * result + age;
return result;
}
}
public static void main(String[] args) {
System.out.println(new User("Ada", 36).hashCode());
}
}आदिम प्रकारों का hash बनाना
हर आदिम प्रकार के hash बनाने का एक सुझाया गया तरीका है:
int: स्वयं मान का उपयोग करें।long:(int)(value ^ (value >>> 32))।boolean: 1 या 0।double:Double.hashCode(value)।
public class Main {
public static void main(String[] args) {
long id = 4_000_000_000L;
int longHash = (int) (id ^ (id >>> 32));
System.out.println("long hash: " + longHash);
System.out.println("double hash: " + Double.hashCode(3.14));
System.out.println("bool hash: " + Boolean.hashCode(true));
}
}सरणियों का hash बनाना
किसी सरणी पर सीधे hashCode() न चलाएँ; यह सामग्री के बजाय पहचान का उपयोग करता है।
सपाट सरणी के लिए Arrays.hashCode(arr) या नेस्टेड सरणियों के लिए Arrays.deepHashCode(arr) का उपयोग करें।
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println("identity equal: " + (a.hashCode() == b.hashCode()));
System.out.println("content equal: " + (Arrays.hashCode(a) == Arrays.hashCode(b)));
}
}equals और hashCode में तालमेल रखें
hashCode() में उपयोग किए गए फ़ील्ड, equals() में उपयोग किए गए फ़ील्ड का उपसमुच्चय होने चाहिए (आदर्श रूप से दोनों में बिल्कुल समान फ़ील्ड होने चाहिए)।
यदि equals, hashCode की तुलना में अधिक फ़ील्ड की तुलना करता है, तो दो समान वस्तुओं का hash फिर भी समान रहेगा। यह अनुमत है। लेकिन यदि hashCode में ऐसा फ़ील्ड उपयोग किया गया है जिसे equals अनदेखा करता है, तो आप अनुबंध तोड़ देते हैं।
import java.util.Objects;
public class Main {
static class Coord {
final int x, y;
Coord(int x, int y) { this.x = x; this.y = y; }
@Override public boolean equals(Object o) {
return o instanceof Coord c && c.x == x && c.y == y;
}
@Override public int hashCode() { return Objects.hash(x, y); }
}
public static void main(String[] args) {
Coord a = new Coord(3, 4), b = new Coord(3, 4);
System.out.println(a.equals(b) && a.hashCode() == b.hashCode());
}
}hash को संचित करना
महँगे hash की गणना वाली अपरिवर्तनीय वस्तुओं के लिए आप परिणाम को किसी फ़ील्ड में संचित कर सकते हैं।
String आंतरिक रूप से ठीक यही करता है। ऐसा तभी करें जब वस्तु वास्तव में अपरिवर्तनीय हो, ताकि संचित मान कभी पुराना न हो।
import java.util.Objects;
public class Main {
static final class Key {
final String a, b;
private int hash; // 0 until computed
Key(String a, String b) { this.a = a; this.b = b; }
@Override public int hashCode() {
int h = hash;
if (h == 0) { h = Objects.hash(a, b); hash = h; }
return h;
}
}
public static void main(String[] args) {
Key k = new Key("x", "y");
System.out.println(k.hashCode());
System.out.println(k.hashCode());
}
}वितरण महत्वपूर्ण है
अच्छी तरह वितरित hashCode कुंजियों को बकेटों में समान रूप से फैलाता है। आइए, वस्तुओं के एक समूह के लिए अलग-अलग hash कोड गिनें।
अलग-अलग मान जितने अधिक होंगे, टकराव उतने ही कम होंगे और मानचित्र उतना ही तेज़ होगा।
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
public class Main {
record Pair(int a, int b) {}
public static void main(String[] args) {
Set<Integer> hashes = new HashSet<>();
for (int i = 0; i < 100; i++) {
hashes.add(Objects.hash(i, i * 7));
}
System.out.println("distinct hashes: " + hashes.size());
}
}Bad वितरण का एक उदाहरण
फ़ील्ड को गुणा किए बिना जोड़ने से टकराव पैदा होते हैं: (1,2) और (2,1) दोनों का hash 3 बनता है।
31 का गुणक इस सममिति को तोड़ देता है, क्योंकि इसके बाद क्रम महत्वपूर्ण हो जाता है।
public class Main {
static int badHash(int a, int b) { return a + b; }
static int goodHash(int a, int b) { return 31 * a + b; }
public static void main(String[] args) {
System.out.println("bad (1,2): " + badHash(1, 2) + ", (2,1): " + badHash(2, 1));
System.out.println("good (1,2): " + goodHash(1, 2) + ", (2,1): " + goodHash(2, 1));
}
}मान-प्रकारों के लिए रिकॉर्ड को प्राथमिकता दें
केवल डेटा रखने वाले वर्गों के लिए record अपने-आप सही और अच्छी तरह वितरित hashCode बना देता है।
हाथ से hashCode तभी लिखें जब आपको कस्टम अर्थविज्ञान की आवश्यकता हो या आप रिकॉर्ड का उपयोग न कर सकें।
public class Main {
record Money(long cents, String currency) {}
public static void main(String[] args) {
Money a = new Money(1099, "USD");
Money b = new Money(1099, "USD");
System.out.println(a.equals(b));
System.out.println(a.hashCode() == b.hashCode());
}
}सब कुछ एक साथ
एक पूर्ण मान-वर्ग: अपरिवर्तनीय फ़ील्ड, समान फ़ील्ड से बनाए गए equals और hashCode, तथा एक सुव्यवस्थित toString।
import java.util.Objects;
public class Main {
static final class Version {
final int major, minor, patch;
Version(int major, int minor, int patch) {
this.major = major; this.minor = minor; this.patch = patch;
}
@Override public boolean equals(Object o) {
return o instanceof Version v && v.major == major && v.minor == minor && v.patch == patch;
}
@Override public int hashCode() { return Objects.hash(major, minor, patch); }
@Override public String toString() { return major + "." + minor + "." + patch; }
}
public static void main(String[] args) {
Version v = new Version(2, 1, 0);
System.out.println(v + " hash=" + v.hashCode());
}
}त्वरित जाँच
अपने hashCode कौशल की जाँच करें।
पुनरावलोकन
आपने hashCode को सही ढंग से लागू करना सीखा:
- सामान्य स्थिति के लिए
Objects.hash(...)का उपयोग करें। - हाथ से hash बनाने के लिए 31 गुणक वाले तरीके का उपयोग करें।
- सरणियों का hash डिफ़ॉल्ट तरीके के बजाय
Arrays.hashCodeसे बनाएँ। - hashCode के फ़ील्ड का equals के साथ तालमेल रखें और रिकॉर्ड को प्राथमिकता दें।
अगले भाग में देखें कि Java 8+ अधिक भरे हुए बकेटों को वृक्षों में कैसे बदलता है।
import java.util.Objects;
public class Main {
public static void main(String[] args) {
System.out.println("hashCode recap done: " + Objects.hash("done"));
}
}एआई शिक्षक के साथ Java सीखें — निःशुल्क
अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।
- पाठ्यक्रम
- 104
- पाठ
- 374
अक्सर पूछे जाने वाले प्रश्न
क्या “hashCode लागू करना” पाठ निःशुल्क है?
हाँ—“hashCode लागू करना” का पूरा पाठ यहाँ वेब पर निःशुल्क पढ़ा जा सकता है। इंटरैक्टिव अभ्यास (अंतर्निहित कोड संपादक और 24/7 एआई ट्यूटर) करने और Java Academy पाठ्यक्रम का बाकी हिस्सा अनलॉक करने के लिए CoddyKit PRO लें। Java Academy पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
“hashCode लागू करना” में मैं क्या सीखूँगा?
सही hash फ़ंक्शन लिखें आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ Java Academy का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।
क्या Java Academy शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?
पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर Java Academy शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 3वाँ पाठ है।
“hashCode लागू करना” पाठ पूरा करने में कितना समय लगता है?
CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।
क्या मैं इस Java Academy पाठ में कोड लिख और चला सकता हूँ?
हाँ। हर Java Academy पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।
इस पाठ्यक्रम के सभी पाठ
- HashMap कैसे काम करता है
- equals/hashCode अनुबंध
- hashCode लागू करना
- Treeification और प्रदर्शन