मुझे इस बात की परवाह क्यों करनी चाहिए कि जावा में जेनेरिकों का पुनरीक्षण नहीं है?


102

यह एक प्रश्न के रूप में आया था जो मैंने हाल ही में एक साक्षात्कार में पूछा था कि कुछ उम्मीदवार जावा भाषा में जोड़ा देखना चाहते थे। यह आमतौर पर एक दर्द के रूप में पहचाना जाता है कि जावा में जेनेरिकों का पुनरीक्षण नहीं किया गया है , लेकिन जब धक्का दिया जाता है, तो उम्मीदवार वास्तव में मुझे उस तरह की चीजें नहीं बता सकते हैं जो वह हासिल कर सकते थे वे वहां थे।

जाहिर है क्योंकि जावा (और असुरक्षित चेक) में कच्चे प्रकार स्वीकार्य हैं, लेकिन जेनरिक को तोड़ना और List<Integer>उस के साथ अंत करना संभव है (उदाहरण के लिए) वास्तव में Stringएस। यह स्पष्ट रूप से असंभव प्रस्तुत किया जा सकता है प्रकार की जानकारी को पुन: प्रमाणित किया गया; लेकिन इस से अधिक होना चाहिए !

क्या लोग उन चीजों के उदाहरण पोस्ट कर सकते हैं जो वे वास्तव में करना चाहते हैं , क्या जेनेरिक उपलब्ध थे? मेरा मतलब है, जाहिर है कि आप एक Listरनटाइम के प्रकार प्राप्त कर सकते हैं - लेकिन आप इसके साथ क्या करेंगे?

public <T> void foo(List<T> l) {
   if (l.getGenericType() == Integer.class) {
       //yeah baby! err, what now?

संपादित करें : उत्तर के रूप में इसका एक त्वरित अद्यतन मुख्य Classरूप से एक पैरामीटर (उदाहरण के लिए EnumSet.noneOf(TimeUnit.class)) के रूप में पारित करने की आवश्यकता के बारे में चिंतित प्रतीत होता है । मैं जहाँ यह संभव नहीं है की तर्ज पर कुछ के लिए और अधिक देख रहा था । उदाहरण के लिए:

List<?> l1 = api.gimmeAList();
List<?> l2 = api.gimmeAnotherList();

if (l1.getGenericType().isAssignableFrom(l2.getGenericType())) {
    l1.addAll(l2); //why on earth would I be doing this anyway?

क्या इसका मतलब यह होगा कि आप एक सामान्य प्रकार के वर्ग को रनटाइम पर प्राप्त कर सकते हैं? (यदि हां, तो मेरे पास एक उदाहरण है!)
जेम्स बी

मुझे लगता है कि पुन: प्रयोज्य जेनेरिक के साथ अधिकांश इच्छाएं उन लोगों से हैं जो मुख्य रूप से संग्रह के साथ जेनेरिक का उपयोग करते हैं, और चाहते हैं कि वे संग्रह अधिक सरणियों की तरह व्यवहार करें।
kdgregory

2
अधिक दिलचस्प सवाल (मेरे लिए): जावा में C ++ स्टाइल जेनरिक को लागू करने में क्या लगेगा? यह निश्चित रूप से रनटाइम में सक्षम लगता है, लेकिन सभी मौजूदा क्लास लोडर को तोड़ देगा (क्योंकि findClass()पैरामीटर में अनदेखी करना होगा, लेकिन defineClass()नहीं कर सकता)। और जैसा कि हम जानते हैं, द पावर्स बी बी बैकवर्ड कम्पैटिबिलिटी सर्वोपरि है।
kdgregory

1
वास्तव में, जावा बहुत ही प्रतिबंधित तरीके से संशोधित जेनरिक प्रदान करता है । मैं इस SO थ्रेड में अधिक जानकारी प्रदान करता हूं: stackoverflow.com/questions/879855/…
रिचर्ड गोम्स

JavaOne मुख्य इंगित करता है कि जावा 9 reification का समर्थन करेंगे।
रंगी कीन

जवाबों:


81

कुछ समय से जो मुझे इस "ज़रूरत" के बारे में पता चला, यह अंततः इस निर्माण के लिए उबलता है:

public class Foo<T> {

    private T t;

    public Foo() {
        this.t = new T(); // Help?
    }

}

यह C # यह मानते हुए काम करता है कि Tएक डिफ़ॉल्ट कंस्ट्रक्टर है। तुम भी रनटाइम प्रकार प्राप्त कर सकते हैं typeof(T)और निर्माणकर्ताओं द्वारा प्राप्त कर सकते हैं Type.GetConstructor()

आम जावा समाधान Class<T>तर्क के रूप में पारित किया जाएगा ।

public class Foo<T> {

    private T t;

    public Foo(Class<T> cls) throws Exception {
        this.t = cls.newInstance();
    }

}

(यह जरूरी नहीं है कि निर्माण तर्क के रूप में पारित किया जाए, क्योंकि विधि तर्क भी ठीक है, ऊपर सिर्फ एक उदाहरण है, try-catchसंक्षिप्तता के लिए भी छोड़ दिया गया है)

अन्य सभी सामान्य प्रकार के निर्माणों के लिए, वास्तविक प्रकार को प्रतिबिंब की थोड़ी मदद से आसानी से हल किया जा सकता है। नीचे Q & A उपयोग मामलों और संभावनाओं का वर्णन करता है:


5
यह काम करता है (उदाहरण के लिए) C # में? आपको कैसे पता चलेगा कि T का डिफॉल्ट कंस्ट्रक्टर है?
थॉमस जंग

4
हाँ, ऐसा करो। और यह सिर्फ एक मूल उदाहरण है (मान लें कि हम जावबीन के साथ काम करते हैं)। पूरे मुद्दा यह है कि जावा के साथ नहीं कक्षा के दौरान प्राप्त कर सकते हैं क्रम से T.classया T.getClass(), ताकि आप सभी अपने खेतों, निर्माताओं और तरीकों का उपयोग कर सकते हैं। यह निर्माण को भी असंभव बनाता है।
बालुसक

3
यह मुझे "बड़ी समस्या" के रूप में वास्तव में कमजोर लगता है, विशेष रूप से यह केवल निर्माणकर्ताओं / मापदंडों आदि के आसपास कुछ बहुत भंगुर प्रतिबिंब के साथ संयोजन में उपयोगी होने की संभावना है
ऑक्सीबो_लैक्स

33
यह C # में संकलित करता है बशर्ते कि आप इस प्रकार की घोषणा करें: सार्वजनिक वर्ग फू <टी> जहां टी: नया ()। जो कि उन प्रकार के टी को सीमित करेगा जो एक पैरामीटर रहित निर्माता होते हैं।
मार्टिन हैरिस

3
@ कोलिन आप वास्तव में जावा को बता सकते हैं कि किसी दिए गए सामान्य प्रकार को एक से अधिक वर्ग या इंटरफ़ेस का विस्तार करने की आवश्यकता है। Docs.oracle.com/javase/tutorial/java/generics/bounded.html के "एकाधिक सीमाएं " अनुभाग देखें । (बेशक, आप यह नहीं बता सकते हैं कि ऑब्जेक्ट एक विशिष्ट सेट में से एक होगा जो उन तरीकों को साझा नहीं करता है जिन्हें एक इंटरफ़ेस में सार किया जा सकता है, जिसे टेम्पलेट विशेषज्ञता का उपयोग करके C ++ में कुछ हद तक लागू किया जा सकता है।)
JAB

99

वह चीज जो मुझे सबसे ज्यादा काटती है वह है कई सामान्य प्रकारों में कई प्रेषण का लाभ उठाने की अक्षमता। निम्नलिखित संभव नहीं है और ऐसे कई मामले हैं जहां यह सबसे अच्छा समाधान होगा:

public void my_method(List<String> input) { ... }
public void my_method(List<Integer> input) { ... }

5
ऐसा करने में सक्षम होने के लिए पुनरीक्षण की कोई आवश्यकता नहीं है। कंपाइल-टाइम टाइप की जानकारी उपलब्ध होने पर कंपाइल समय पर मेथड सिलेक्शन किया जाता है।
टॉम हॉकिन -

26
@Tom: यह टाइप इरेज़र के कारण भी संकलित नहीं होता है। दोनों के रूप में संकलित public void my_method(List input) {}। मैं हालांकि इस जरूरत के लिए कभी नहीं आया, सिर्फ इसलिए कि उनका एक ही नाम नहीं होगा। यदि उनका नाम समान है, तो मैं public <T extends Object> void my_method(List<T> input) {}बेहतर विचार नहीं होने पर सवाल करूंगा ।
बालुस

1
हम्म, मैं पूरी तरह से मानकों के समान संख्या के साथ अधिक भार से बचने के लिए जाते हैं, और की तरह कुछ पसंद करते हैं myStringsMethod(List<String> input)और myIntegersMethod(List<Integer> input)यहां तक कि अगर इस तरह के एक मामले के लिए अधिक भार जावा में संभव हो गया था।
फेबियन स्टिग

4
@ फ़ेबियन: जिसका अर्थ है कि आपके पास अलग कोड है, और <algorithm>सी ++ से मिलने वाले लाभों को रोकें ।
डेविड थॉर्नले

मैं भ्रमित हूं, यह अनिवार्य रूप से मेरे दूसरे बिंदु के समान है, फिर भी मुझे इस पर 2 डाउनवोट मिले? किसी को मेरी कल्पना करने की परवाह है?
आरएसपी

34

टाइप सेफ्टी का ख्याल आता है। पैरामीट्रिक प्रकार के डाउनकास्टिंग को हमेशा सामान्यीकृत जनन के बिना असुरक्षित किया जाएगा:

List<String> myFriends = new ArrayList();
myFriends.add("Alice");
getSession().put("friends", myFriends);
// later, elsewhere
List<Friend> myFriends = (List<Friend>) getSession().get("friends");
myFriends.add(new Friend("Bob")); // works like a charm!
// and so...
List<String> myFriends = (List<String>) getSession().get("friends");
for (String friend : myFriends) print(friend); // ClassCastException, wtf!? 

इसके अलावा, अमूर्त कम लीक करेंगे - कम से कम जो उनके प्रकार के मापदंडों के बारे में रनटाइम जानकारी में रुचि हो सकती है। आज, यदि आपको किसी भी सामान्य पैरामीटर के प्रकार के बारे में किसी भी प्रकार की रनटाइम जानकारी की आवश्यकता है, तो आपको इसके Classसाथ ही पास करना होगा । इस तरह, आपका बाहरी इंटरफ़ेस आपके कार्यान्वयन पर निर्भर करता है (चाहे आप अपने मापदंडों के बारे में RTTI का उपयोग करें या नहीं)।


1
हां - मेरे पास इसका एक तरीका है कि मैं ParametrizedListस्रोत संग्रह जाँच प्रकारों में डेटा की प्रतिलिपि बनाता हूं । यह थोड़ा सा पसंद है Collections.checkedListलेकिन एक संग्रह के साथ शुरू करने के लिए वरीयता प्राप्त किया जा सकता है।
oxbow_lakes

@ टैकलाइन - ठीक है, कुछ अमूर्त कम रिसाव होगा। यदि आपको अपने कार्यान्वयन में मेटाडेटा टाइप करने की आवश्यकता है, तो बाहरी इंटरफ़ेस आप पर बताएगा क्योंकि क्लाइंट को आपको एक क्लास ऑब्जेक्ट भेजने की आवश्यकता है।
gustafc

... इसका मतलब है कि संशोधित जेनरिक के साथ, आप बाहरी इंटरफ़ेस को बदले बिना T.class.getAnnotation(MyAnnotation.class)( जैसे Tकि एक सामान्य प्रकार) सामान जोड़ सकते हैं ।
gustafc 14

@gustafc: यदि आपको लगता है कि C ++ टेम्पलेट आपको पूरी तरह से सुरक्षा देते हैं, तो इसे पढ़ें: kdgregory.com/index.php?page=java.generics.cpp
kdgregory

@kdgregory: मैंने कभी नहीं कहा कि C ++ 100% सुरक्षित था - बस उस मिटाने से सुरक्षा के प्रकार बिगड़ जाते हैं। जैसा कि आप स्वयं कहते हैं, "C ++, यह पता चला है, इसकी अपनी प्रकार की अपरिपक्वता है, जिसे C- शैली सूचक कास्ट के रूप में जाना जाता है।" लेकिन जावा केवल डायनेमिक कास्ट्स (रिइंटरप्रिटेटिंग नहीं) करता है, इसलिए रिविजन इस पूरे को टाइप सिस्टम में प्लग करेगा।
gustafc

26

आप अपने कोड में जेनेरिक सरणियाँ बनाने में सक्षम होंगे।

public <T> static void DoStuff() {
    T[] myArray = new T[42]; // No can do
}

ऑब्जेक्ट में क्या गलत है? वस्तुओं की एक सरणी किसी भी तरह से संदर्भों की सरणी है। यह ऐसा नहीं है कि ऑब्जेक्ट डेटा स्टैक पर बैठा है - यह ढेर में है।
रैन बीरन

19
प्रकार की सुरक्षा। मैं ऑब्जेक्ट में जो कुछ भी चाहता हूं [] डाल सकता हूं, लेकिन स्ट्रिंग्स में केवल स्ट्रिंग्स []।
टर्नर

3
भागा: व्यंग्यात्मक हुए बिना: आप जावा के बजाय एक स्क्रिप्टिंग भाषा का उपयोग करना पसंद कर सकते हैं, तो आपके पास कहीं भी अप्राप्त संस्करण का लचीलापन है!
भेड़

2
Arrays दोनों भाषाओं में सहसंयोजक (और इसलिए नहीं असुरक्षित) हैं। String[] strings = new String[1]; Object[] objects = strings; objects[0] = new Object();दोनों भाषाओं में ठीक संकलन। नोटोफाइन चलाता है।
मार्टिनेज

16

यह एक पुराना प्रश्न है, उत्तर के एक टन हैं, लेकिन मुझे लगता है कि मौजूदा उत्तर निशान से दूर हैं।

"reified" का अर्थ वास्तविक है और आमतौर पर इसका अर्थ है केवल प्रकार के विलोम के विपरीत।

जावा जेनरिक से जुड़ी बड़ी समस्या:

  • यह भयानक मुक्केबाजी की आवश्यकता है और आदिम और संदर्भ प्रकारों के बीच काटता है। यह सीधे तौर पर संशोधन या मिटाने से संबंधित नहीं है। C # / Scala इसे ठीक करें।
  • कोई स्व प्रकार नहीं। JavaFX 8 को इस कारण से "बिल्डरों" को हटाना पड़ा। टाइप इरेज़र से कोई लेना देना नहीं है। Scala इसे ठीक करता है, C # के बारे में निश्चित नहीं है।
  • कोई घोषणा पक्ष प्रकार भिन्नता नहीं। C # 4.0 / Scala है। टाइप इरेज़र से कोई लेना देना नहीं है।
  • अधिभार void method(List<A> l)और नहीं कर सकते method(List<B> l)। यह प्रकार के क्षरण के कारण होता है लेकिन अत्यंत क्षुद्र है।
  • रनटाइम प्रकार प्रतिबिंब के लिए कोई समर्थन नहीं। यह प्रकार के उन्मूलन का दिल है। यदि आप सुपर एडवांस कंपाइलर पसंद करते हैं जो संकलन समय पर आपके प्रोग्राम लॉजिक को अधिक से अधिक सत्यापित और प्रमाणित करते हैं, तो आपको यथासंभव कम प्रतिबिंब का उपयोग करना चाहिए और इस प्रकार के इरेज़र आपको परेशान नहीं करना चाहिए। यदि आप अधिक पैची, पटकथा, गतिशील प्रकार की प्रोग्रामिंग पसंद करते हैं और एक कंपाइलर के बारे में इतना ध्यान नहीं रखते हैं कि आपके तर्क जितना संभव हो उतना सही साबित होता है, तो आप बेहतर प्रतिबिंब चाहते हैं और प्रकार के क्षरण को ठीक करना महत्वपूर्ण है।

1
ज्यादातर मुझे सीरियलाइजेशन के मामले काफी मुश्किल लगते हैं। आप अक्सर श्रेणीबद्ध चीज़ों को क्रमबद्ध रूप से प्राप्त करने में सक्षम होना चाहेंगे, लेकिन प्रकार के क्षरण के कारण आपको कम रोका जा सकता है। इस तरह से कुछ करना कठिन हो जाता हैdeserialize(thingy, List<Integer>.class)
कॉगमैन

3
मुझे लगता है कि यह सबसे अच्छा जवाब है। विशेष रूप से यह वर्णन करते हुए कि क्या मुद्दे वास्तव में मौलिक रूप से प्रकार के क्षरण के कारण हैं और क्या सिर्फ जावा भाषा की डिज़ाइन समस्याएं हैं। पहली बात जो मैं लोगों को इरेज़र-व्हाइनिंग शुरू करने के लिए कहता हूं, वह यह है कि स्काला और हास्केल टाइप इरेज़र द्वारा भी काम कर रहे हैं।
anemxdp

13

सत्यापन के साथ सीरियलाइज़ेशन अधिक सरल होगा। हम जो चाहते हैं, वह है

deserialize(thingy, List<Integer>.class);

हमें क्या करना है

deserialize(thing, new TypeReference<List<Integer>>(){});

बदसूरत दिखता है और मज़ेदार तरीके से काम करता है।

ऐसे मामले भी हैं जहां कुछ कहना वास्तव में उपयोगी होगा

public <T> void doThings(List<T> thingy) {
    if (T instanceof Q)
      doCrazyness();
  }

ये चीजें अक्सर नहीं काटती हैं, लेकिन ऐसा होने पर वे काटती हैं।


यह। एक हजार बार यह। हर बार जब मैं जावा में डीरियलाइज़ेशन कोड लिखने की कोशिश करता हूं तो मैं उस दिन को व्यतीत करता हूं जो मैं किसी और चीज में काम नहीं कर रहा हूं
बेसिक

11

Java Geneircs के लिए मेरा एक्सपोज़र काफी सीमित है, और उन बिंदुओं के अलावा अन्य उत्तर पहले ही उल्लेख कर चुके हैं कि मॉरीस नैफ्टालिन और फिलिप वाल्डर की पुस्तक जावा जेनरिक एंड कलेक्शंस में एक ऐसा परिदृश्य बताया गया है , जहाँ संशोधित जेनरिक उपयोगी है।

चूंकि प्रकार reifiable नहीं हैं, इसलिए Parameterized अपवाद होना संभव नहीं है।

उदाहरण के लिए नीचे दिए गए फॉर्म की घोषणा वैध नहीं है।

class ParametericException<T> extends Exception // compile error

ऐसा इसलिए है क्योंकि कैच क्लॉज यह जांचता है कि फेंका गया अपवाद किसी दिए गए प्रकार से मेल खाता है या नहीं। यह जांच उसी तरह की है जैसे कि उदाहरण परीक्षण द्वारा किया गया चेक और चूंकि प्रकार स्वीकार्य नहीं है, इसलिए उपरोक्त कथन अमान्य है।

यदि उपरोक्त कोड मान्य था, तो नीचे दिए गए तरीके से अपवाद संभालना संभव होगा:

try {
     throw new ParametericException<Integer>(42);
} catch (ParametericException<Integer> e) { // compile error
  ...
}

पुस्तक में यह भी उल्लेख किया गया है कि यदि जावा जेनरिक को C ++ टेम्प्लेट के रूप में परिभाषित किया गया है (विस्तार) तो यह अधिक कुशल कार्यान्वयन हो सकता है क्योंकि यह अनुकूलन के लिए अधिक अवसर प्रदान करता है। लेकिन इससे अधिक कोई स्पष्टीकरण नहीं दिया जाता है, इसलिए जानकार लोगों से कोई भी स्पष्टीकरण (संकेत) मददगार होगा।


1
यह एक मान्य बिंदु है, लेकिन मुझे यकीन नहीं है कि क्यों एक अपवाद वर्ग इतना पैरामीरिड उपयोगी होगा। क्या आप अपने उत्तर को संशोधित कर सकते हैं कि यह कब उपयोगी हो सकता है?
oxbow_lakes

@oxbow_lakes: क्षमा करें, जावा जेनरिक का मेरा ज्ञान काफी सीमित है और मैं इस पर सुधार करने का प्रयास कर रहा हूं। इसलिए अब मैं किसी भी उदाहरण के बारे में नहीं सोच पा रहा हूं, जहां पैराट्राइज्ड अपवाद उपयोगी हो सकता है। इसके बारे में सोचने की कोशिश करेंगे। धन्यवाद।
शतेश १ s

यह अपवाद प्रकारों के कई उत्तराधिकार के विकल्प के रूप में कार्य कर सकता है।
मैरिटॉन

प्रदर्शन इम्प्रूवमेंट यह है कि वर्तमान में, एक प्रकार का पैरामीटर ऑब्जेक्ट से इनहेरिट करना चाहिए, जिसमें आदिम प्रकार के बॉक्सिंग की आवश्यकता होती है, जो एक निष्पादन और मेमोरी ओवरहेड लगाता है।
मैरिटॉन

8

Arrays शायद जेनेरिक के साथ बहुत अच्छे खेलेंगे अगर वे पुनरीक्षित थे।


2
ज़रूर, लेकिन उन्हें अभी भी समस्या होगी। List<String>एक नहीं है List<Object>
टॉम हॉल्टिन -

सहमत - लेकिन केवल आदिम (पूर्णांक, दीर्घ, आदि) के लिए। "नियमित" ऑब्जेक्ट के लिए, यह समान है। चूंकि प्राइमिटिज़ एक पैरामीटर प्रकार (अधिक गंभीर समस्या, कम से कम IMHO) नहीं हो सकता है, मैं इसे वास्तविक दर्द के रूप में नहीं देखता हूं।
रैन बीरन

3
सरणियों के साथ समस्या उनके सहसंयोजक है, जो कुछ भी नहीं करना है।
बजे

5

मेरे पास एक आवरण है जो एक jdbc परिणाम को पुनरावृत्त के रूप में प्रस्तुत करता है, (इसका अर्थ है कि मैं डेटाबेस-परीक्षण किए गए ऑपरेशनों को निर्भरता इंजेक्शन के माध्यम से बहुत आसान कर सकता हूं)।

एपीआई ऐसा दिखता है Iterator<T>जहां टी कुछ प्रकार है जिसका निर्माण कंस्ट्रक्टर में केवल तार का उपयोग करके किया जा सकता है। Iterator तब sql क्वेरी से लौटाए जा रहे तार को देखता है और फिर उसे T के कंस्ट्रक्टर से मिलाने की कोशिश करता है।

वर्तमान में जिस तरह से जेनरिक को लागू किया जाता है, मुझे उन वस्तुओं के वर्ग में भी पास होना होगा जिन्हें मैं अपने परिणाम से बना रहा हूं। यदि मैं सही ढंग से समझता हूं, अगर जेनरिक को पुन: निर्धारित किया गया था, तो मैं सिर्फ T.getClass () को इसके निर्माणकर्ता कह सकता हूं, और फिर Class.newInstance () का परिणाम नहीं देना होगा, जो कि बहुत अधिक पुराना होगा।

असल में, मुझे लगता है कि यह एपीआई लिखना (केवल एक आवेदन लिखने के विपरीत) आसान बनाता है, क्योंकि आप वस्तुओं से बहुत अधिक अनुमान लगा सकते हैं, और इस तरह से कम कॉन्फ़िगरेशन आवश्यक होगा ... मैंने एनोटेशन के निहितार्थ की सराहना नहीं की जब तक कि मैं देखा कि उन्हें विन्यास के स्थानों के बजाय बसंत या झरने जैसी चीजों में इस्तेमाल किया जा रहा है।


लेकिन कक्षा में पास होना मेरे लिए हर समय सुरक्षित है। किसी भी स्थिति में, डेटाबेस प्रश्नों से परावर्तनशील रूप से परिवर्तन करना बहुत ही भंगुर होता है, जैसे कि वैसे भी (जैसे आपके कोड और डेटाबेस दोनों में) रिफैक्टिंग करना। मुझे लगता है कि मैं उन चीजों की तलाश कर रहा था
जिनके

5

एक अच्छी बात आदिम (मूल्य) प्रकारों के लिए मुक्केबाजी से बचना होगा। यह कुछ हद तक उस सरणी शिकायत से संबंधित है जिसे अन्य लोगों ने उठाया है, और ऐसे मामलों में जहां मेमोरी का उपयोग बाधित है, यह वास्तव में एक महत्वपूर्ण अंतर बना सकता है।

फ्रेमवर्क लिखते समय कई प्रकार की समस्याएं भी होती हैं, जहां पैरामीटर प्रकार पर प्रतिबिंबित करने में सक्षम होना महत्वपूर्ण है। बेशक यह रनटाइम के आसपास एक क्लास ऑब्जेक्ट को पास करके काम किया जा सकता है, लेकिन यह एपीआई को अस्पष्ट करता है और फ्रेमवर्क के उपयोगकर्ता पर एक अतिरिक्त बोझ डालता है।


2
यह मूल रूप से ऐसा करने में सक्षम है new T[]जहां टी आदिम प्रकार का है!
oxbow_lakes 11

2

ऐसा नहीं है कि आप कुछ भी असाधारण हासिल करेंगे। इसे समझना सरल होगा। टाइप इरेज़र शुरुआती लोगों के लिए एक कठिन समय की तरह लगता है, और इसे अंततः कंपाइलर के काम करने के तरीके पर किसी की समझ की आवश्यकता होती है।

मेरी राय है, कि जेनरिक बस एक अतिरिक्त है जो बहुत सारे अनावश्यक कास्टिंग बचाता है।


यह निश्चित रूप से जावा में जेनेरिक हैं । C # और अन्य भाषाओं में वे एक शक्तिशाली उपकरण हैं
मूल

1

कुछ ऐसा है कि यहाँ सभी उत्तर छूट गए हैं जो लगातार मेरे लिए सिरदर्द है क्योंकि प्रकार मिटा दिए जाते हैं, आप दो बार एक सामान्य इंटरफ़ेस नहीं ले सकते। यह एक समस्या हो सकती है जब आप ठीक दाने वाले इंटरफेस बनाना चाहते हैं।

    public interface Service<KEY,VALUE> {
           VALUE get(KEY key);
    }

    public class PersonService implements Service<Long, Person>,
        Service<String, Person> //Can not do!!

0

यहां एक ऐसा है जो आज मुझे पकड़ा गया है: बिना किसी संशोधन के, यदि आप एक ऐसी विधि लिखते हैं, जो सामान्य वस्तुओं की एक वैगरह सूची को स्वीकार करती है ... कॉल करने वाले वे टाइप कर सकते हैं, लेकिन गलती से किसी पुराने क्रूड में गुजर जाते हैं, और अपनी विधि को उड़ा देते हैं।

लगता है कि ऐसा नहीं होगा? ... यकीन है, जब तक ... आप अपने डेटाटाइप के रूप में कक्षा का उपयोग करें। इस बिंदु पर, आपका कॉलर ख़ुशी से आपको बहुत सारी क्लास ऑब्जेक्ट भेजेगा, लेकिन एक साधारण टाइपो आपको क्लास ऑब्जेक्ट भेजेगा जो टी का पालन नहीं करता है, और आपदा हमले।

(NB: मैंने यहां एक गलती की है, लेकिन "जेनेरिक वर्गास" के आसपास गुगली करना, उपरोक्त वही प्रतीत होता है जो आप उम्मीद करेंगे। यह एक व्यावहारिक समस्या है जो क्लास का उपयोग करती है, मुझे लगता है - कॉलर्स लगते हैं कम सावधान रहना :()


उदाहरण के लिए, मैं एक प्रतिमान का उपयोग कर रहा हूं जो मानचित्र में क्लास ऑब्जेक्ट का उपयोग करता है (यह एक साधारण नक्शे की तुलना में अधिक जटिल है - लेकिन वैचारिक रूप से यही चल रहा है)।

उदाहरण के लिए, यह जावा जेनरिक (तुच्छ उदाहरण) में महान काम करता है:

public <T extends Component> Set<UUID> getEntitiesPossessingComponent( Class<T> componentType)
    {
        // find the entities that are mapped (somehow) from that class. Very type-safe
    }

उदाहरण के लिए जावा जेनरिक में, यह कोई भी "क्लास" ऑब्जेक्ट स्वीकार करता है। और यह पिछले कोड का केवल एक छोटा विस्तार है:

public <T extends Component> Set<UUID> getEntitiesPossessingComponents( Class<T>... componentType )
    {
        // find the entities that are mapped (somehow) to ALL of those classes
    }

उपरोक्त तरीकों को एक व्यक्तिगत परियोजना में हजारों बार लिखा जाना है - इसलिए मानव त्रुटि की संभावना अधिक हो जाती है। डिबगिंग की गलतियाँ "मज़ेदार नहीं" साबित हो रही हैं। मैं वर्तमान में एक विकल्प खोजने की कोशिश कर रहा हूं, लेकिन बहुत उम्मीद नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.