नमस्ते! आज हम वस्तुओं की तुलना करने के बारे में बात करने जा रहे हैं। हम्म... लेकिन क्या हमने इस विषय पर एक से अधिक बार बात नहीं की है? : / हम जानते हैं कि
==
ऑपरेटर कैसे काम करता है, साथ ही साथ equals()
और hashCode()
तरीके भी। तुलना थोड़ी अलग है। पहले, हमारा सबसे अधिक मतलब "समानता के लिए वस्तुओं की जाँच" था। लेकिन वस्तुओं की एक दूसरे से तुलना करने के कारण पूरी तरह से अलग हो सकते हैं! इनमें से सबसे स्पष्ट छँटाई है। मुझे लगता है कि अगर आपको संख्याओं या तारों को क्रमबद्ध करने के लिए कहा गया था ArrayList<>
, तो आप बिना किसी समस्या के इसे संभालने में सक्षम होंगे:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
String name1 = "Masha";
String name2 = "Sasha";
String name3 = "Dasha";
List<String> names = new ArrayList<>();
names.add(name1);
names.add(name2);
names.add(name3);
Collections.sort(names);
System.out.println(names);
}
}
कंसोल आउटपुट:
[Dasha, Masha, Sasha]
यदि आपको Collections
कक्षा और उसकी sort()
विधि याद है, तो बहुत अच्छा! मुझे लगता है कि आपको नंबरों को लेकर भी कोई परेशानी नहीं होगी। यहां आपके लिए एक और चुनौतीपूर्ण कार्य है:
public class Car {
private int manufactureYear;
private String model;
private int maxSpeed;
public Car(int manufactureYear, String model, int maxSpeed) {
this.manufactureYear = manufactureYear;
this.model = model;
this.maxSpeed = maxSpeed;
}
// ...getters, setters, toString()
}
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Car> cars = new ArrayList<>();
Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
Car bugatti = new Car(2010, "Bugatti Veyron", 350);
cars.add(ferrari);
cars.add(bugatti);
cars.add(lambo);
}
}
कार्य वास्तव में सरल है। हमारे पास एक Car
क्लास और 3 कार ऑब्जेक्ट हैं। क्या आप कृपया कारों को सूची में क्रमबद्ध करेंगे? आप शायद पूछेंगे, "उन्हें कैसे छाँटना चाहिए?" नाम से? निर्माण के वर्ष से? अधिकतम गति से? बेहतरीन सवाल। इस समय, हम नहीं जानते कि Car
वस्तुओं को कैसे क्रमित करना है। और, स्वाभाविक रूप से, जावा यह भी नहीं जानता है! जब हम वस्तुओं की सूची को विधि Car
में पास करने का प्रयास करते हैं Collections.sort()
, तो हमें एक त्रुटि मिलती है:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Car> cars = new ArrayList<>();
Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
Car lambo = new Car(20012, "Lamborghini Gallardo", 290);
Car bugatti = new Car(2010, "Bugatti Veyron", 350);
cars.add(ferrari);
cars.add(bugatti);
cars.add(lambo);
// Compilation error!
Collections.sort(cars);
}
}
और वास्तव में, भाषा को कैसे पता चलेगा कि आपके द्वारा लिखी गई कक्षाओं की वस्तुओं को कैसे क्रमबद्ध किया जाए? यह इस बात पर निर्भर करता है कि आपके प्रोग्राम को क्या करने की आवश्यकता है। इन वस्तुओं की तुलना करने के लिए हमें किसी तरह जावा को सिखाना चाहिए। और उनकी तुलना करने के लिए कि हम कैसे चाहते हैं। इसके लिए जावा में एक विशेष तंत्र है: Comparable
इंटरफ़ेस। किसी तरह हमारी वस्तुओं की तुलना और क्रमबद्ध करने के लिए Car
, वर्ग को इस इंटरफ़ेस को लागू करना चाहिए, जिसमें एक विधि शामिल है compareTo()
:
public class Car implements Comparable<Car> {
private int manufactureYear;
private String model;
private int maxSpeed;
public Car(int manufactureYear, String model, int maxSpeed) {
this.manufactureYear = manufactureYear;
this.model = model;
this.maxSpeed = maxSpeed;
}
@Override
public int compareTo(Car o) {
return 0;
}
// ...getters, setters, toString()
}
कृपया ध्यानकि हमने Comparable<Car>
इंटरफ़ेस निर्दिष्ट किया है, न कि केवल Comparable
. यह एक पैरामिट्रीकृत इंटरफ़ेस है, अर्थात हमें विशिष्ट संबद्ध वर्ग को निर्दिष्ट करना होगा। सिद्धांत रूप में, आप <Car>
इंटरफ़ेस से हटा सकते हैं, लेकिन तब तुलना Object
डिफ़ॉल्ट रूप से वस्तुओं पर आधारित होगी। विधि के बजाय compareTo(Car o)
, हमारी कक्षा में होगा:
@Override
public int compareTo(Object o) {
return 0;
}
बेशक, हमारे साथ काम करना बहुत आसान है Car
। विधि के अंदर compareTo()
, हम कारों की तुलना करने के लिए अपने तर्क को लागू करते हैं। मान लीजिए हमें उन्हें निर्माण के वर्ष के अनुसार क्रमबद्ध करने की आवश्यकता है। आपने शायद ध्यान दिया है कि compareTo()
विधि a लौटाती है int
, न कि a boolean
। इससे आप हैरान मत होइए। जब हम दो वस्तुओं की तुलना करते हैं, तो तीन संभावनाएँ होती हैं:
а < b
a > b
a == b
.
boolean
केवल 2 मान हैं: सत्य और असत्य, जो वस्तुओं की तुलना करने के लिए अच्छा काम नहीं करता है। के साथ int
, सब कुछ बहुत सरल है। यदि वापसी मूल्य है > 0
, तो a > b
। यदि का परिणाम compareTo
है < 0
, तो a < b
। और, यदि परिणाम है == 0
, तो दो वस्तुएँ समान हैं a == b
:। हमारी कक्षा को निर्माण के वर्ष के अनुसार कारों को छाँटना सिखाना आसान है:
@Override
public int compareTo(Car o) {
return this.getManufactureYear() - o.getManufactureYear();
}
लेकिन यहाँ क्या हो रहा है? हम एक कार वस्तु ( this
) लेते हैं, इस कार के निर्माण का वर्ष प्राप्त करते हैं, और उसमें से दूसरी कार के निर्माण का वर्ष घटाते हैं (वह वस्तु जिसके साथ वस्तु की तुलना की जा रही है)। यदि पहली कार के निर्माण का वर्ष अधिक है, तो विधि एक int > 0
. इसका मतलब है कि this car >
कार o
। इसके विपरीत, यदि दूसरी कार ( ) के निर्माण का वर्ष о
अधिक है, तो विधि एक ऋणात्मक संख्या वापस करेगी, जिसका अर्थ है कि o > this
। अंत में, यदि वे समान हैं, तो विधि वापस आ जाएगी 0
। Car
वस्तुओं के संग्रह को क्रमबद्ध करने के लिए यह सरल तंत्र पहले से ही पर्याप्त है ! आपको और कुछ नहीं करना है। इसकी जांच - पड़ताल करें:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Car> cars = new ArrayList<>();
Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
Car bugatti = new Car(2010, "Bugatti Veyron", 350);
cars.add(ferrari);
cars.add(bugatti);
cars.add(lambo);
// There was previously an error here
Collections.sort(cars);
System.out.println(cars);
}
}
कंसोल आउटपुट:
[Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310},
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350},
Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290}]
कारों को वैसे ही सॉर्ट किया जाता है जैसे हम चाहते हैं! :) मुझे कब उपयोग करना चाहिए Comparable
? में लागू की गई तुलना पद्धति को Comparable
प्राकृतिक क्रम कहा जाता है। ऐसा इसलिए है क्योंकि इस पद्धति में compareTo()
आप इस वर्ग की वस्तुओं की तुलना करने के सबसे सामान्य या प्राकृतिक तरीके को परिभाषित करते हैं। जावा में पहले से ही एक प्राकृतिक क्रम है। उदाहरण के लिए, जावा जानता है कि तारों को अक्सर वर्णानुक्रम में क्रमबद्ध किया जाता है, और संख्याएँ संख्यात्मक मान बढ़ाकर। इसलिए, यदि आप sort()
विधि को संख्याओं या स्ट्रिंग्स की सूची पर कॉल करते हैं, तो उन्हें सॉर्ट किया जाएगा। यदि हमारा कार्यक्रम आमतौर पर निर्माण के वर्ष के अनुसार कारों की तुलना और वर्गीकरण करेगा, तो हमें इंटरफ़ेस का उपयोग करके कारों के लिए प्राकृतिक छँटाई को परिभाषित करना चाहिए Comparable<Car>
औरcompareTo()
तरीका। लेकिन क्या होगा अगर यह हमारे लिए पर्याप्त नहीं है? आइए कल्पना करें कि हमारा कार्यक्रम इतना सरल नहीं है। ज्यादातर मामलों में, कारों की प्राकृतिक छँटाई (जो हमने निर्माण के वर्ष तक करने के लिए निर्धारित की है) हमें सूट करती है। लेकिन कभी-कभी हमारे ग्राहक तेज ड्राइविंग के शौकीन होते हैं। अगर हम उनके पढ़ने के लिए कार कैटलॉग तैयार कर रहे हैं, तो कारों को अधिकतम गति से क्रमबद्ध किया जाना चाहिए। उदाहरण के लिए, मान लीजिए कि हमें 15% समय इस तरह छाँटने की आवश्यकता है। यह स्पष्ट रूप से हमारे लिए Car
निर्माण के वर्ष के बजाय गति के आधार पर वर्ग की प्राकृतिक छँटाई निर्धारित करने के लिए पर्याप्त नहीं है। लेकिन हम अपने 15% ग्राहकों की उपेक्षा नहीं कर सकते। तो हम क्या करें? एक अन्य इंटरफ़ेस यहाँ हमारी सहायता के लिए आता है: Comparator
. ठीक वैसे ही Comparable
, यह एक पैरामिट्रीकृत इंटरफ़ेस है। क्या फर्क पड़ता है? Comparable
हमारी वस्तुओं को "तुलनीय" बनाता है और उनके सबसे प्राकृतिक क्रम क्रम को परिभाषित करता है, अर्थात वह क्रम जो ज्यादातर मामलों में उपयोग किया जाएगा। Comparator
एक अलग "तुलना" इंटरफ़ेस है। Car
यदि हमें किसी प्रकार के विशेष छँटाई क्रम को लागू करने की आवश्यकता है, तो हमें कक्षा में जाने और तर्क को बदलने की आवश्यकता नहीं है compareTo()
। इसके बजाय, हम एक अलग वर्ग बना सकते हैं जो तुलनित्र को लागू करता है और यह सिखाता है कि हमें जिस तरह की छँटाई करनी है उसे कैसे करना है!
import java.util.Comparator;
public class MaxSpeedCarComparator implements Comparator<Car> {
@Override
public int compare(Car o1, Car o2) {
return o1.getMaxSpeed() - o2.getMaxSpeed();
}
}
जैसा कि आप देख सकते हैं, हमारा Comparator
बहुत सरल है। हमें केवल एक इंटरफ़ेस विधि को लागू करने की आवश्यकता है: compare()
. यह दो Car
वस्तुओं को इनपुट के रूप में लेता है और सामान्य तरीके से (घटाव द्वारा) उनकी अधिकतम गति की तुलना करता है। जैसे compareTo()
, यह a लौटाता है int
, और तुलना का सिद्धांत समान है। हम इसका उपयोग कैसे करते हैं? यह सब सीधा है:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Car> cars = new ArrayList<>();
Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
Car bugatti = new Car(2010, "Bugatti Veyron", 350);
cars.add(ferrari);
cars.add(bugatti);
cars.add(lambo);
Comparator speedComparator = new MaxSpeedCarComparator();
Collections.sort(cars, speedComparator);
System.out.println(cars);
}
}
कंसोल आउटपुट:
[Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290},
Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310},
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350}]
हम केवल एक तुलनित्र वस्तु बनाते हैं और इसे Collections.sort()
सॉर्ट की जाने वाली सूची के साथ विधि में पास करते हैं। जब विधि एक तुलनित्र प्राप्त करती है, तो यह कक्षा की विधि sort()
में परिभाषित प्राकृतिक छँटाई का उपयोग नहीं करती है । इसके बजाय, यह पास किए गए तुलनित्र द्वारा परिभाषित छँटाई एल्गोरिथ्म को लागू करता है। ऐसा करने के क्या फायदे हैं? सबसे पहले, मौजूदा कोड के साथ संगतता। हमने एक नई, विशेष छँटाई विधि बनाई है, जबकि मौजूदा विधि को बनाए रखा है जिसका अधिकांश समय उपयोग किया जाएगा। हमने कक्षा को बिल्कुल नहीं छुआ । यह एक था , और इसलिए यह बना हुआ है: Car
compareTo()
Car
Comparable
public class Car implements Comparable<Car> {
private int manufactureYear;
private String model;
private int maxSpeed;
public Car(int manufactureYear, String model, int maxSpeed) {
this.manufactureYear = manufactureYear;
this.model = model;
this.maxSpeed = maxSpeed;
}
@Override
public int compareTo(Car o) {
return this.getManufactureYear() - o.getManufactureYear();
}
// ...getters, setters, toString()
}
दूसरा, लचीलापन। हम जितने चाहें उतने सॉर्टिंग एल्गोरिदम जोड़ सकते हैं। उदाहरण के लिए, हम कारों को रंग, गति, वजन, या बैटमैन फिल्मों में कितनी बार कार का उपयोग किया गया है, के आधार पर सॉर्ट कर सकते हैं। हमें बस इतना करना है कि एक अतिरिक्त Comparator
. इतना ही! आज आपने दो बहुत महत्वपूर्ण तंत्रों का अध्ययन किया है जिनका उपयोग आप अक्सर वास्तविक परियोजनाओं में काम पर करेंगे। लेकिन, जैसा कि आप जानते हैं, अभ्यास के बिना सिद्धांत कुछ भी नहीं है। अब आपके ज्ञान को मजबूत करने और कुछ कार्यों को पूरा करने का समय आ गया है!
GO TO FULL VERSION