हाय! आजच्या धड्यात, आम्ही जेनेरिकचा अभ्यास सुरू ठेवू. हे जसे घडते तसे, हा एक मोठा विषय आहे, परंतु याला टाळता येत नाही — हा भाषेचा एक अत्यंत महत्त्वाचा भाग आहे :) जेव्हा तुम्ही जेनेरिकवरील ओरॅकल दस्तऐवजीकरणाचा अभ्यास करता किंवा ऑनलाइन ट्यूटोरियल वाचता, तेव्हा तुम्हाला नॉन-रिफायेबल प्रकार आणि अटी आढळतील. refiable प्रकार . रीफिएबल प्रकार हा एक प्रकार आहे ज्यासाठी रनटाइमवर माहिती पूर्णपणे उपलब्ध असते. जावामध्ये, अशा प्रकारांमध्ये आदिम, कच्चे प्रकार आणि नॉन-जेनेरिक प्रकारांचा समावेश होतो. याउलट, नॉन-रिफिएबल प्रकार असे प्रकार आहेत ज्यांची माहिती मिटवली जाते आणि रनटाइमच्या वेळी अगम्य बनते. जसे घडते, हे जेनेरिक आहेत —
List<String>
, List<Integer>
इ.
बाय द वे, वारर्ग्स म्हणजे काय ते आठवतंय का?
जर तुम्ही विसरलात, तर हा व्हेरिएबल-लांबीचा युक्तिवाद आहे. आमच्या पद्धतीत किती युक्तिवाद पास केले जाऊ शकतात हे आम्हाला माहित नसते अशा परिस्थितीत ते उपयुक्त आहेत. उदाहरणार्थ, जर आपल्याकडे कॅल्क्युलेटर वर्ग असेल ज्यामध्येsum
पद्धत आहे. पद्धत sum()
2, किंवा 3, किंवा 5, किंवा आपल्याला पाहिजे तितके प्राप्त करू शकते. sum()
प्रत्येक संभाव्य वितर्कांसाठी पद्धत ओव्हरलोड करणे खूप विचित्र असेल . त्याऐवजी, आम्ही हे करू शकतो:
public class SimpleCalculator {
public static int sum(int...numbers) {
int result = 0;
for(int i : numbers) {
result += i;
}
return result;
}
public static void main(String[] args) {
System.out.println(sum(1,2,3,4,5));
System.out.println(sum(2,9));
}
}
कन्सोल आउटपुट:
15
11
हे आम्हाला दर्शविते की जेनेरिकसह varargs वापरताना काही महत्त्वाची वैशिष्ट्ये आहेत. चला खालील कोड पाहू:
import javafx.util.Pair;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static <E> void addAll(List<E> list, E... array) {
for (E element : array) {
list.add(element);
}
}
public static void main(String[] args) {
addAll(new ArrayList<String>(), // This is okay
"Leonardo da Vinci",
"Vasco de Gama"
);
// but here we get a warning
addAll(new ArrayList<Pair<String, String>>(),
new Pair<String, String>("Leonardo", "da Vinci"),
new Pair<String, String>("Vasco", "de Gama")
);
}
}
पद्धत addAll()
इनपुट a List<E>
आणि कितीही E
ऑब्जेक्ट्स घेते आणि नंतर ती या सर्व ऑब्जेक्ट्सला सूचीमध्ये जोडते. पद्धतीमध्ये main()
, आम्ही आमच्या addAll()
पद्धतीला दोनदा कॉल करतो. पहिल्या प्रकरणात, आम्ही मध्ये दोन सामान्य स्ट्रिंग जोडतो List
. येथे सर्व काही व्यवस्थित आहे. दुस-या बाबतीत, आम्ही दोन Pair<String, String>
ऑब्जेक्ट्स मध्ये जोडतो List
. परंतु येथे आम्हाला अनपेक्षितपणे एक चेतावणी प्राप्त झाली:
Unchecked generics array creation for varargs parameter
याचा अर्थ काय? आम्हाला चेतावणी का मिळते आणि तेथे एखाद्याचा उल्लेख का आहे array
? शेवटी, आमच्या कोडमध्ये नाही array
! चला दुसऱ्या केसपासून सुरुवात करूया. चेतावणी अॅरेचा उल्लेख करते कारण कंपाइलर व्हेरिएबल-लेंथ आर्ग्युमेंट (varargs) अॅरेमध्ये रूपांतरित करतो. दुसऱ्या शब्दांत, आमच्या पद्धतीची स्वाक्षरी addAll()
आहे:
public static <E> void addAll(List<E> list, E... array)
हे प्रत्यक्षात असे दिसते:
public static <E> void addAll(List<E> list, E[] array)
म्हणजेच, मेथडमध्ये main()
, कंपाइलर आमचा कोड यामध्ये रूपांतरित करतो:
public static void main(String[] args) {
addAll(new ArrayList<String>(),
new String[] {
"Leonardo da Vinci",
"Vasco de Gama"
}
);
addAll(new ArrayList<Pair<String,String>>(),
new Pair<String,String>[] {
new Pair<String,String>("Leonardo","da Vinci"),
new Pair<String,String>("Vasco","de Gama")
}
);
}
अॅरे String
फक्त ठीक आहे. पण Pair<String, String>
अॅरे नाही. समस्या अशी आहे की Pair<String, String>
एक नॉन-रिफिएबल प्रकार आहे. संकलनादरम्यान, प्रकार वितर्कांबद्दलची सर्व माहिती (<स्ट्रिंग, स्ट्रिंग>) मिटवली जाते. Java मध्ये नॉन-रिफायेबल प्रकाराचे अॅरे तयार करण्याची परवानगी नाही . तुम्ही व्यक्तिचलितपणे Pair<String, String> अॅरे तयार करण्याचा प्रयत्न केल्यास तुम्ही हे पाहू शकता
public static void main(String[] args) {
// Compilation error Generic array creation
Pair<String, String>[] array = new Pair<String, String>[10];
}
कारण स्पष्ट आहे: प्रकार सुरक्षितता. तुम्हाला आठवत असेल, अॅरे तयार करताना, अॅरे कोणत्या वस्तू (किंवा आदिम) संग्रहित करेल हे निश्चितपणे नमूद करावे लागेल.
int array[] = new int[10];
आमच्या मागील धड्यांपैकी एकामध्ये, आम्ही इरेजरचे तपशीलवार परीक्षण केले. Pair
या प्रकरणात, टाइप इरेजरमुळे ऑब्जेक्ट्स जोड्या संग्रहित करते ती माहिती गमावते <String, String>
. अॅरे तयार करणे असुरक्षित असेल. varargs आणि जेनेरिक यांचा समावेश असलेल्या पद्धती वापरताना , टाइप इरेजर आणि ते कसे कार्य करते हे लक्षात ठेवण्याची खात्री करा. तुम्ही लिहिलेल्या कोडबद्दल तुम्हाला पूर्ण खात्री असल्यास आणि त्यामुळे कोणतीही समस्या उद्भवणार नाही हे तुम्हाला माहीत असल्यास, तुम्ही भाष्ये वापरून varargs-संबंधित इशारे बंद करू शकता . @SafeVarargs
@SafeVarargs
public static <E> void addAll(List<E> list, E... array) {
for (E element : array) {
list.add(element);
}
}
तुम्ही तुमच्या पद्धतीमध्ये हे भाष्य जोडल्यास, आम्हाला पूर्वी आलेली चेतावणी दिसणार नाही. जेनेरिकसह varargs वापरताना उद्भवू शकणारी आणखी एक समस्या म्हणजे ढीग प्रदूषण. ढीग प्रदूषण खालील परिस्थितीत होऊ शकते:
import java.util.ArrayList;
import java.util.List;
public class Main {
static List<String> polluteHeap() {
List numbers = new ArrayList<Number>();
numbers.add(1);
List<String> strings = numbers;
strings.add("");
return strings;
}
public static void main(String[] args) {
List<String> stringsWithHeapPollution = polluteHeap();
System.out.println(stringsWithHeapPollution.get(0));
}
}
कन्सोल आउटपुट:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
सोप्या भाषेत, ढीग प्रदूषण म्हणजे जेव्हा प्रकारची वस्तू A
ढीगमध्ये असावी, परंतु B
प्रकार सुरक्षिततेशी संबंधित त्रुटींमुळे प्रकारची वस्तू तेथेच संपते. आमच्या उदाहरणात, हे तंतोतंत घडते. प्रथम, आम्ही रॉ व्हेरिएबल तयार केले आणि त्यास numbers
सामान्य संग्रह ( ) नियुक्त केले . मग आम्ही संग्रहात ArrayList<Number>
संख्या जोडली .1
List<String> strings = numbers;
या ओळीवर, कंपाइलरने " अनचेक असाइनमेंट... " चेतावणी जारी करून आम्हाला संभाव्य त्रुटींबद्दल चेतावणी देण्याचा प्रयत्न केला, परंतु आम्ही त्याकडे दुर्लक्ष केले. आम्ही प्रकाराच्या जेनेरिक व्हेरिएबलसह समाप्त होतो List<String>
जे प्रकाराच्या सामान्य संग्रहाकडे निर्देश करते ArrayList<Number>
. स्पष्टपणे, या परिस्थितीमुळे त्रास होऊ शकतो! आणि तसे ते करते. आमचे नवीन व्हेरिएबल वापरून, आम्ही संग्रहामध्ये एक स्ट्रिंग जोडतो. आमच्याकडे आता ढीग प्रदूषण आहे — आम्ही पॅरामेट्रीज्ड कलेक्शनमध्ये एक संख्या आणि नंतर एक स्ट्रिंग जोडली. कंपाइलरने आम्हाला चेतावणी दिली, परंतु आम्ही त्याच्या चेतावणीकडे दुर्लक्ष केले. परिणामी, ClassCastException
प्रोग्राम चालू असतानाच आम्हाला मिळते. मग याचा वरगांशी काय संबंध? जेनेरिकसह varargs वापरल्याने सहजपणे ढीग प्रदूषण होऊ शकते. येथे एक साधे उदाहरण आहे:
import java.util.Arrays;
import java.util.List;
public class Main {
static void polluteHeap(List<String>... stringsLists) {
Object[] array = stringsLists;
List<Integer> numbersList = Arrays.asList(66,22,44,12);
array[0] = numbersList;
String str = stringsLists[0].get(0);
}
public static void main(String[] args) {
List<String> cars1 = Arrays.asList("Ford", "Fiat", "Kia");
List<String> cars2 = Arrays.asList("Ferrari", "Bugatti", "Zaporozhets");
polluteHeap(cars1, cars2);
}
}
इथे काय चालले आहे? टाइप इरेजरमुळे, आमचा व्हेरिएबल-लांबीचा युक्तिवाद
List<String>...stringsLists
सूचीचे अॅरे बनते, म्हणजे List[]
, अज्ञात प्रकारच्या वस्तूंचे (विसरू नका की संकलनादरम्यान varargs नियमित अॅरेमध्ये बदलतात). यामुळे, आम्ही ते Object[] array
पद्धतीच्या पहिल्या ओळीतील व्हेरिएबलला सहजपणे नियुक्त करू शकतो — आमच्या सूचीतील ऑब्जेक्ट्सचा प्रकार मिटवला गेला आहे! आणि आता आपल्याकडे एक Object[]
व्हेरिएबल आहे, ज्यामध्ये आपण काहीही जोडू शकतो, कारण Java मधील सर्व ऑब्जेक्ट्स इनहेरिट आहेत Object
! सुरुवातीला, आमच्याकडे फक्त स्ट्रिंग्सची सूची आहे. पण इरेजर टाइप केल्याबद्दल आणि varargs चा वापर केल्याबद्दल धन्यवाद, आम्ही सहज संख्यांची यादी जोडू शकतो, जी आम्ही करतो. परिणामी, आपण विविध प्रकारच्या वस्तूंचे मिश्रण करून ढीग प्रदूषित करतो. ClassCastException
जेव्हा आपण अॅरेमधून स्ट्रिंग वाचण्याचा प्रयत्न करतो तेव्हा परिणाम आणखी एक होईल . कन्सोल आउटपुट:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
असे अनपेक्षित परिणाम varargs वापरून होऊ शकतात, एक वरवर सोपी यंत्रणा :) आणि त्यासोबतच, आजचा धडा संपतो. काही कार्ये सोडविण्यास विसरू नका आणि जर तुमच्याकडे वेळ आणि शक्ती असेल तर काही अतिरिक्त वाचन अभ्यासा. " प्रभावी Java " स्वतः वाचणार नाही! :) पुढच्या वेळे पर्यंत!
GO TO FULL VERSION