CodeGym /Java Blog /यादृच्छिक /जावा मध्ये जेनेरिक
John Squirrels
पातळी 41
San Francisco

जावा मध्ये जेनेरिक

यादृच्छिक या ग्रुपमध्ये प्रकाशित केले
हाय! आपण जावा जेनेरिक्स बद्दल बोलणार आहोत. मी म्हणायलाच पाहिजे की तू खूप काही शिकशील! केवळ हा धडाच नाही तर पुढील काही धडेही जेनेरिकला वाहिले जातील. त्यामुळे, तुम्हाला जेनेरिकमध्ये स्वारस्य असल्यास, आजचा दिवस तुमचा भाग्यशाली दिवस आहे: तुम्हाला जेनेरिकच्या वैशिष्ट्यांबद्दल बरेच काही शिकायला मिळेल. आणि नसेल तर स्वतः राजीनामा द्या आणि आराम करा! :) हा एक अतिशय महत्वाचा विषय आहे, आणि तुम्हाला तो माहित असणे आवश्यक आहे. चला सोप्यापासून सुरुवात करूया: "काय" आणि "का".

जावा जेनेरिक्स म्हणजे काय?

जेनेरिक्स असे प्रकार आहेत ज्यांचे पॅरामीटर असते. जेनेरिक प्रकार तयार करताना, तुम्ही केवळ एक प्रकारच नाही तर डेटा प्रकार देखील निर्दिष्ट करता ज्यासह ते कार्य करेल. माझा अंदाज आहे की सर्वात स्पष्ट उदाहरण तुमच्या मनात आधीच आले आहे: ArrayList! अशा प्रकारे आम्ही प्रोग्राममध्ये एक तयार करतो:

import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<String> myList1 = new ArrayList<>();
       myList1.add("Test String 1");
       myList1.add("Test String 2");
   }
}
तुम्ही अंदाज लावू शकता की, या सूचीचे वैशिष्ट्य म्हणजे आम्ही त्यात सर्वकाही भरू शकत नाही: ते केवळ स्ट्रिंग ऑब्जेक्ट्ससह कार्य करते. आता जावाच्या इतिहासात थोडे विषयांतर करून "का?" या प्रश्नाचे उत्तर देण्याचा प्रयत्न करूया. हे करण्यासाठी, आम्ही ArrayList वर्गाची आमची स्वतःची सरलीकृत आवृत्ती लिहू. आमच्या सूचीला फक्त डेटा कसा जोडायचा आणि अंतर्गत अॅरेमधून डेटा कसा मिळवायचा हे माहित आहे:

public class MyListClass {

   private Object[] data;
   private int count;

   public MyListClass() {
       this.data = new Object[10];
       this.count = 0;
   }

   public void add(Object o) {
       this.data[count] = o;
       count++;
   }

   public Object[] getData() {
       return data;
   }
}
समजा आमची यादी फक्त पूर्णांक s संग्रहित करायची आहे. आम्ही सामान्य प्रकार वापरत नाही. आम्ही add() पद्धतीमध्ये स्पष्ट "Instanceof Integer " चेक समाविष्ट करू इच्छित नाही . जर आम्ही असे केले तर आमचा संपूर्ण वर्ग केवळ पूर्णांकासाठी योग्य असेल आणि आम्हाला जगातील प्रत्येक डेटा प्रकारासाठी समान वर्ग लिहावा लागेल! आम्ही आमच्या प्रोग्रामरवर विसंबून राहू आणि त्यांनी आम्हाला नको असलेले काहीही जोडले नाही याची खात्री करण्यासाठी कोडमध्ये फक्त एक टिप्पणी द्या:

// Use this class ONLY with the Integer data type
public void add(Object o) {
   this.data[count] = o;
   count++;
}
एका प्रोग्रामरने ही टिप्पणी चुकवली आणि अनवधानाने संख्यांच्या सूचीमध्ये अनेक स्ट्रिंग्स टाकल्या आणि नंतर त्यांची बेरीज केली:

public class Main {

   public static void main(String[] args) {

       MyListClass list = new MyListClass();
       list.add(100);
       list.add(200);
       list.add("Lolkek");
       list.add("Shalala");

       Integer sum1 = (Integer) list.getData()[0] + (Integer) list.getData()[1];
       System.out.println(sum1);

       Integer sum2 = (Integer) list.getData()[2] + (Integer) list.getData()[3];
       System.out.println(sum2);
   }
}
कन्सोल आउटपुट:

300 
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
      at Main.main (Main.java:14)
या परिस्थितीचा सर्वात वाईट भाग कोणता आहे? प्रोग्रामरचा निष्काळजीपणा नक्कीच नाही. सर्वात वाईट भाग असा आहे की चुकीचा कोड आमच्या प्रोग्राममध्ये एका महत्त्वाच्या ठिकाणी संपला आणि यशस्वीरित्या संकलित झाला. आता आम्हाला कोड लिहिताना बग आढळेल, परंतु केवळ चाचणी दरम्यान (आणि ही सर्वोत्तम परिस्थिती आहे!). विकासाच्या नंतरच्या टप्प्यात दोषांचे निराकरण करण्यासाठी खूप जास्त खर्च येतो — पैसा आणि वेळ या दोन्ही बाबतीत. येथेच जेनेरिकचा आपल्याला फायदा होतो: एक सामान्य वर्ग दुर्दैवी प्रोग्रामरला लगेच त्रुटी शोधू देतो. कार्यक्रम फक्त संकलित होणार नाही!

import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Integer> myList1 = new ArrayList<>();
      
       myList1.add(100);
       myList1.add(100);
       myList1.add ("Lolkek"); // Error!
       myList1.add("Shalala"); // Error!
   }
}
प्रोग्रामरला त्याची चूक ताबडतोब लक्षात येते आणि तो लगेच बरा होतो. तसे, या प्रकारची त्रुटी पाहण्यासाठी आम्हाला आमचा स्वतःचा यादी वर्ग तयार करण्याची गरज नाही. फक्त कोन कंस काढा आणि सामान्य ArrayList मधून ( <Integer> ) टाइप करा!

import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

      List list = new ArrayList();

      list.add(100);
      list.add(200);
      list.add("Lolkek");
      list.add("Shalala");

       System.out.println((Integer) list.get(0) + (Integer) list.get(1));
       System.out.println((Integer) list.get(2) + (Integer) list.get(3));
   }
}
कन्सोल आउटपुट:

300 
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
     at Main.main(Main.java:16)
दुसऱ्या शब्दांत, Java ची "नेटिव्ह" यंत्रणा वापरूनही, आम्ही अशा प्रकारची चूक करू शकतो आणि एक असुरक्षित संग्रह तयार करू शकतो. तथापि, आम्ही हा कोड IDE मध्ये पेस्ट केल्यास, आम्हाला एक चेतावणी मिळेल: "कच्च्या प्रकारच्या java.util.List चे सदस्य म्हणून जोडण्यासाठी अनचेक केलेला कॉल" आयटम जोडताना काहीतरी चूक होऊ शकते असे आम्हाला सांगितले जाते. जेनेरिक प्रकार नसलेल्या संग्रहासाठी. पण "कच्चा प्रकार" या वाक्यांशाचा अर्थ काय आहे? कच्चा प्रकार हा एक सामान्य वर्ग आहे ज्याचा प्रकार काढला गेला आहे. दुसऱ्या शब्दांत, List myList1 हा कच्चा प्रकार आहे . कच्च्या प्रकाराच्या विरुद्ध एक सामान्य प्रकार आहे — पॅरामीटराइज्ड प्रकार(चे) दर्शविणारा एक सामान्य वर्ग . उदाहरणार्थ, List<String> myList1. आपण विचारू शकता की भाषा कच्च्या प्रकारांच्या वापरास परवानगी का देते ? कारण सोपे आहे. सुसंगतता समस्या निर्माण होऊ नये म्हणून Java च्या निर्मात्यांनी भाषेतील कच्च्या प्रकारांसाठी समर्थन सोडले. Java 5.0 रिलीझ होईपर्यंत (जेनेरिक प्रथम या आवृत्तीमध्ये दिसले), कच्चे प्रकार वापरून बरेच कोड आधीच लिहिले गेले होते . परिणामी, ही यंत्रणा आजही समर्थित आहे. आम्ही धड्यांमध्ये जोशुआ ब्लोचच्या क्लासिक पुस्तक "प्रभावी जावा" चा वारंवार उल्लेख केला आहे. भाषेच्या निर्मात्यांपैकी एक म्हणून, त्यांनी त्यांच्या पुस्तकात कच्चे प्रकार आणि सामान्य प्रकार वगळले नाहीत.Java मध्ये जेनेरिक काय आहेत?  - 2पुस्तकाच्या 23 व्या अध्यायात एक अतिशय स्पष्ट शीर्षक आहे: "नवीन कोडमध्ये कच्चे प्रकार वापरू नका" हे तुम्हाला लक्षात ठेवणे आवश्यक आहे. जेनेरिक वर्ग वापरताना, जेनेरिक प्रकाराला कच्च्या प्रकारात कधीही बदलू नका .

सामान्य पद्धती

Java तुम्हाला तथाकथित जेनेरिक पद्धती तयार करून वैयक्तिक पद्धतींचे पॅरामीटराइज करू देते. अशा पद्धती कशा उपयुक्त आहेत? सर्वात महत्त्वाचे म्हणजे, ते आपल्याला विविध प्रकारच्या पद्धती पॅरामीटर्ससह कार्य करू देतात यासाठी उपयुक्त आहेत. जर समान तर्कशास्त्र वेगवेगळ्या प्रकारांवर सुरक्षितपणे लागू केले जाऊ शकते, तर एक सामान्य पद्धत हा एक उत्तम उपाय असू शकतो. हे अगदी साधे उदाहरण विचारात घ्या: समजा आपल्याकडे myList1 नावाची काही यादी आहे . आम्हाला सूचीमधून सर्व मूल्ये काढून टाकायची आहेत आणि सर्व रिकाम्या जागा नवीन मूल्यांनी भरायच्या आहेत. आमचा वर्ग सामान्य पद्धतीने कसा दिसतो ते येथे आहे:

public class TestClass {

   public static <T> void fill(List<T> list, T val) {
       for (int i = 0; i < list.size(); i++)
           list.set(i, val);
   }

   public static void main(String[] args) {

       List<String> strings = new ArrayList<>();
       strings.add("Old String 1");
       strings.add("Old String 2");
       strings.add("Old String 3");

       fill(strings, "New String");

       System.out.println(strings);

       List<Integer> numbers = new ArrayList<>();
       numbers.add(1);
       numbers.add(2);
       numbers.add(3);

       fill(numbers, 888);
       System.out.println(numbers);
   }
}
वाक्यरचनाकडे लक्ष द्या. हे थोडेसे असामान्य दिसते:

public static <T> void fill(List<T> list, T val)
आम्ही रिटर्न टाईपच्या आधी <T> लिहितो. हे सूचित करते की आम्ही एका सामान्य पद्धतीसह व्यवहार करत आहोत. या प्रकरणात, पद्धत इनपुट म्हणून 2 पॅरामीटर्स स्वीकारते: टी ऑब्जेक्ट्सची सूची आणि दुसरा वेगळा टी ऑब्जेक्ट. <T> वापरून, आम्ही पद्धतीचे पॅरामीटर प्रकार पॅरामीटराइज करतो: आम्ही स्ट्रिंग्स आणि पूर्णांक सूचीमध्ये पास करू शकत नाही. स्ट्रिंग्स आणि स्ट्रिंगची सूची, पूर्णांक आणि पूर्णांकांची सूची, आपल्या स्वतःच्या मांजरीच्या वस्तूंची सूची आणि दुसर्‍या मांजरीच्या वस्तूंची यादी - आपल्याला हेच करायचे आहे. मुख्य () पद्धत विविध प्रकारच्या डेटासह कार्य करण्यासाठी fill() पद्धत सहजपणे कशी वापरली जाऊ शकते हे स्पष्ट करते. प्रथम, आम्ही स्ट्रिंग्सची सूची आणि इनपुट म्हणून स्ट्रिंग आणि नंतर पूर्णांक आणि पूर्णांकांच्या सूचीसह पद्धत वापरतो. कन्सोल आउटपुट:

[New String, New String, New String] [888, 888, 888]
कल्पना करा की आमच्याकडे जेनेरिक पद्धती नसतील आणि ३० वेगवेगळ्या वर्गांसाठी fill() पद्धतीच्या तर्काची आवश्यकता असेल. वेगवेगळ्या डेटा प्रकारांसाठी आपल्याला तीच पद्धत 30 वेळा लिहावी लागेल! पण जेनेरिक पद्धतींबद्दल धन्यवाद, आम्ही आमचा कोड पुन्हा वापरू शकतो! :)

सामान्य वर्ग

तुम्ही मानक Java लायब्ररीमध्ये प्रदान केलेल्या सामान्य वर्गांपुरते मर्यादित नाही — तुम्ही तुमचे स्वतःचे तयार करू शकता! येथे एक साधे उदाहरण आहे:

public class Box<T> {

   private T t;

   public void set(T t) {
       this.t = t;
   }

   public T get() {
       return t;
   }

   public static void main(String[] args) {

       Box<String> stringBox = new Box<>();

       stringBox.set("Old String");
       System.out.println(stringBox.get());
       stringBox.set("New String");

       System.out.println(stringBox.get());
      
       stringBox.set(12345); // Compilation error!
   }
}
आमचा बॉक्स<T> वर्ग हा एक सामान्य वर्ग आहे. एकदा आम्ही निर्मिती दरम्यान डेटा प्रकार ( <T> ) नियुक्त केल्यावर, आम्ही त्यामध्ये इतर प्रकारच्या वस्तू ठेवण्यास सक्षम नाही. हे उदाहरणामध्ये पाहिले जाऊ शकते. आमचे ऑब्जेक्ट तयार करताना, आम्ही सूचित केले की ते स्ट्रिंगसह कार्य करेल:

Box<String> stringBox = new Box<>();
आणि कोडच्या शेवटच्या ओळीत, जेव्हा आपण बॉक्समध्ये 12345 क्रमांक ठेवण्याचा प्रयत्न करतो, तेव्हा आपल्याला एक संकलन त्रुटी येते! हे इतके सोपे आहे! आम्ही आमचा स्वतःचा सामान्य वर्ग तयार केला आहे! :) त्याबरोबर आजचा धडा संपला. पण आम्ही जेनेरिकला अलविदा म्हणत नाही! पुढील धड्यांमध्ये, आम्ही अधिक प्रगत वैशिष्ट्यांबद्दल बोलू, म्हणून तुम्ही दूर जाऊ नका! ) तुम्ही जे शिकलात ते अधिक बळकट करण्यासाठी, आम्ही तुम्हाला आमच्या Java कोर्समधून व्हिडिओ धडा पाहण्याची शिफारस करतो
तुमच्या अभ्यासात सर्वोत्तम यश! :)
टिप्पण्या
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION