इसके कारण इस पर आधारित हैं कि जावा जेनिक्स को कैसे लागू करता है।
एक सरणी उदाहरण
सरणियों के साथ आप इस (सरणियों covariant हैं के रूप में दूसरों समझा दिया है)
Integer[] myInts = {1,2,3,4};
Number[] myNumber = myInts;
लेकिन, क्या होगा अगर तुम यह करने के लिए कोशिश कर सकते हैं?
Number[0] = 3.14; //attempt of heap pollution
यह अंतिम पंक्ति ठीक संकलन होगा, लेकिन अगर आप इस कोड को चलाने के लिए, आप एक ArrayStoreException
मिल सकता है। क्योंकि आप एक पूर्णांक सरणी में डबल डालने की कोशिश कर रहे हैं (भले ही किसी संख्या संदर्भ के माध्यम से पहुंचा जा रहा हो)।
इसका मतलब है कि आप संकलक को मूर्ख बना सकते हैं, लेकिन आप रनटाइम प्रकार प्रणाली को मूर्ख नहीं बना सकते हैं। और ऐसा इसलिए है क्योंकि सरणी हम reifiable प्रकार पर कॉल करते हैं। इसका मतलब यह है कि रनटाइम पर जावा जानता है कि इस सरणी को वास्तव में पूर्णांक की सरणी के रूप में तुरंत चालू किया गया था जो कि Number[]
के संदर्भ के माध्यम से आसानी से पहुंचा जा सकता है।
तो, जैसा कि आप देख सकते हैं, एक बात वस्तु का वास्तविक प्रकार है, एक और चीज उस संदर्भ का प्रकार है जिसका उपयोग आप इसे एक्सेस करने के लिए करते हैं, है ना?
जावा जेनेरिक्स
के साथ समस्या अब, जावा सामान्य प्रकार के साथ समस्या यह है कि प्रकार की जानकारी संकलक द्वारा खारिज कर दिया है और यह रन टाइम पर उपलब्ध नहीं है। इस प्रक्रिया को type erasure कहा जाता है। जावा में इस तरह के जेनरिक को लागू करने के लिए अच्छे कारण हैं, लेकिन यह एक लंबी कहानी है, और इसे पूर्व-मौजूदा कोड के साथ बाइनरी संगतता के साथ करना है।
लेकिन यहां महत्वपूर्ण बात यह है कि, रनटाइम पर कोई प्रकार की जानकारी नहीं है, यह सुनिश्चित करने का कोई तरीका नहीं है कि हम ढेर प्रदूषण नहीं कर रहे हैं।
उदाहरण के लिए
,
List<Integer> myInts = new ArrayList<Integer>();
myInts.add(1);
myInts.add(2);
List<Number> myNums = myInts; //compiler error
myNums.add(3.14); //heap polution
जावा कम्पाइलर ऐसा करने से रोक नहीं करता है, क्रम प्रकार प्रणाली या तो आप को रोक नहीं सकते, कोई रास्ता नहीं है क्योंकि वहाँ रनटाइम पर, निर्धारित करने के लिए, जो इस सूची था केवल पूर्णांक की सूची होना चाहिए। जावा रनटाइम आपको जो कुछ भी आप इस सूची में रखना चाहते हैं, उसे केवल पूर्णांक होना चाहिए, क्योंकि जब इसे बनाया गया था, तो इसे पूर्णांक की सूची के रूप में घोषित किया गया था।
इस तरह, जावा के डिजाइनरों ने सुनिश्चित किया कि आप कंपाइलर को मूर्ख नहीं बना सकते हैं। यदि आप कंपाइलर को मूर्ख नहीं बना सकते हैं (जैसा कि हम सरणी के साथ कर सकते हैं) तो आप रनटाइम टाइप सिस्टम को भी मूर्ख नहीं बना सकते हैं।
इस प्रकार, हम कहते हैं कि सामान्य प्रकार गैर-उत्तरदायी हैं।
जाहिर है, यह बहुरूपता में बाधा डालता है।
static long sum(Number[] numbers) {
long summation = 0;
for(Number number : numbers) {
summation += number.longValue();
}
return summation;
}
अब आप इसे इस तरह इस्तेमाल कर सकते हैं:
Integer[] myInts = {1,2,3,4,5};
Long[] myLongs = {1L, 2L, 3L, 4L, 5L};
Double[] myDoubles = {1.0, 2.0, 3.0, 4.0, 5.0};
System.out.println(sum(myInts));
System.out.println(sum(myLongs));
System.out.println(sum(myDoubles));
लेकिन अगर आप सामान्य संग्रह के साथ एक ही कोड लागू करने के लिए प्रयास करते हैं, आप सफल नहीं होगा:
static long sum(List<Number> numbers) {
long summation = 0;
for(Number number : numbers) {
summation += number.longValue();
}
return summation;
}
निम्नलिखित उदाहरण पर विचार
यदि आप कोशिश करते हैं तो आपको कंपाइलर त्रुटि मिल जाएगी ...
List<Integer> myInts = asList(1,2,3,4,5);
List<Long> myLongs = asList(1L, 2L, 3L, 4L, 5L);
List<Double> myDoubles = asList(1.0, 2.0, 3.0, 4.0, 5.0);
System.out.println(sum(myInts)); //compiler error
System.out.println(sum(myLongs)); //compiler error
System.out.println(sum(myDoubles)); //compiler error
समाधान जावा जेनरिक की दो शक्तिशाली विशेषताओं का उपयोग करना सीखना है जो कोविरिएन्स और contravariance के रूप में जाना जाता है।
सहप्रसरण
सहप्रसरण आप एक संरचना से आइटम पढ़ सकते हैं, लेकिन आप इसे में कुछ भी नहीं लिख सकते हैं के साथ। ये सभी वैध घोषणाएं हैं।
List<? extends Number> myNums = new ArrayList<Integer>();
List<? extends Number> myNums = new ArrayList<Float>()
List<? extends Number> myNums = new ArrayList<Double>()
और तुम myNums
से पढ़ सकते हैं:
Number n = myNums.get(0);
क्योंकि आप यह सुनिश्चित करें कि जो कुछ भी वास्तविक सूची है हो सकता है, यह (एक संख्या को upcasted जा सकती है, सब कुछ भी है कि संख्या फैली के बाद एक नंबर , सही?)
हालांकि, आपको किसी भी प्रकार की संरचना में कुछ भी लगाने की अनुमति नहीं है।
myNumst.add(45L); //compiler error
यह अनुमति नहीं दी जाएगी, क्योंकि जावा गारंटी नहीं दे सकता कि सामान्य संरचना में वस्तु का वास्तविक प्रकार क्या है। यह कुछ भी हो सकता है जो संख्या बढ़ाता है, लेकिन संकलक सुनिश्चित नहीं हो सकता है। तो आप पढ़ सकते हैं, लेकिन लिख नहीं सकते।
contravariance
contravariance के साथ आप के सामने कर सकते हैं। आप चीजों को एक सामान्य संरचना में डाल सकते हैं, लेकिन आप इससे बाहर नहीं पढ़ सकते हैं।
List<Object> myObjs = new List<Object();
myObjs.add("Luke");
myObjs.add("Obi-wan");
List<? super Number> myNums = myObjs;
myNums.add(10);
myNums.add(3.14);
इस मामले में, वस्तु की वास्तविक प्रकृति वस्तुओं की एक सूची है, और contravariance के माध्यम से, आप इसे में नंबर डाल सकते हैं, मूल रूप से, क्योंकि सभी नंबरों को उनके पूर्वज के रूप में वस्तु की है। इस प्रकार, सभी संख्या वस्तुएं हैं, और इसलिए यह मान्य है।
हालांकि, आप इस contravariant संरचना से कुछ भी सुरक्षित रूप से पढ़ नहीं सकते हैं मानते हैं कि आपको एक संख्या मिल जाएगी।
Number myNum = myNums.get(0); //compiler-error
आप देख सकते हैं, तो आप इस लाइन लिखने के लिए करता है, तो संकलक की अनुमति दी है, तो आप क्रम में एक ClassCastException मिलेगा।
प्राप्त करें/रखो सिद्धांत
जैसे, सहप्रसरण का उपयोग जब आप केवल एक संरचना के बाहर सामान्य मूल्यों लेने के लिए, contravariance का उपयोग करना चाहते हैं जब आप केवल एक संरचना में सामान्य मूल्यों डाल दिया और सटीक सामान्य उपयोग करना चाहते हैं टाइप करें जब आप दोनों करना चाहते हैं।
मेरे पास सबसे अच्छा उदाहरण निम्न है जो किसी भी प्रकार की संख्या को किसी सूची से दूसरी सूची में कॉपी करता है। यह केवल स्रोत से आइटम प्राप्त करता है, और यह केवल भाग्य में आइटम रखता है।
public static void copy(List<? extends Number> source, List<? super Number> destiny) {
for(Number number : source) {
destiny.add(number);
}
}
सहप्रसरण और contravariance की शक्तियों इस इस तरह के मामले के लिए काम करता है के लिए धन्यवाद:
List<Integer> myInts = asList(1,2,3,4);
List<Double> myDoubles = asList(3.14, 6.28);
List<Object> myObjs = new ArrayList<Object>();
copy(myInts, myObjs);
copy(myDoubles, myObjs);
वहाँ उन लोगों का तर्क था जो सरणियों की इजाजत दी है कि एक बुरा विचार था क्या करना है कि कर रहे हैं। – Jeffrey
मिराज और जेनेरिक टाइप करें, संग्रह नहीं, कारण हैं। – duffymo
संक्षिप्त उत्तर "जेनेरिक कंटेनर सरणी नहीं हैं"। लंबे उत्तर, जैसे डफिमो अलरेड ने सुझाव दिया है, "erasures" है: http://code.stephenmorley.org/articles/java-generics-type-erasure/ – paulsm4