एक कच्चा प्रकार क्या है और हमें इसका उपयोग क्यों नहीं करना चाहिए?


662

प्रशन:

  • जावा में कच्चे प्रकार क्या हैं, और मैं अक्सर क्यों सुनता हूं कि उन्हें नए कोड में उपयोग नहीं किया जाना चाहिए?
  • यदि हम कच्चे प्रकारों का उपयोग नहीं कर सकते हैं, और यह कैसे बेहतर है?

जावा ट्यूटोरियल अभी भी JComboBox का उपयोग करता है जो इस चेतावनी का कारण बनता है। कॉम्बोक्स का कौन सा संस्करण इस चेतावनी का कारण नहीं होगा? docs.oracle.com/javase/tutorial/uiswing/compenders/…
सुपरस्टार

1
ध्यान दें कि कच्चे प्रकार का अस्तित्व जावा 1.4 और पुराने के साथ पीछे की संगतता के लिए है, जिसके पास जेनेरिक बिल्कुल नहीं था।
जेस्पर

जवाबों:


744

एक कच्चा प्रकार क्या है?

जावा भाषा विनिर्देश एक कच्चे प्रकार को परिभाषित करता है:

JLS 4.8 कच्चे प्रकार

कच्चे प्रकार को निम्नलिखित में से एक के रूप में परिभाषित किया गया है:

  • संदर्भ प्रकार जो एक सामान्य प्रकार की घोषणा के साथ एक बिना किसी प्रकार के तर्क सूची के नाम से बनता है।

  • एक सरणी प्रकार जिसका तत्व प्रकार एक कच्चा प्रकार है।

  • एक staticकच्चे सदस्य का एक गैर- सदस्य प्रकार, Rजो सुपरक्लास या सुपरफर्टफेस से विरासत में नहीं मिला है R

यहाँ एक उदाहरण दिया गया है:

public class MyType<E> {
    class Inner { }
    static class Nested { }

    public static void main(String[] args) {
        MyType mt;          // warning: MyType is a raw type
        MyType.Inner inn;   // warning: MyType.Inner is a raw type

        MyType.Nested nest; // no warning: not parameterized type
        MyType<Object> mt1; // no warning: type parameter given
        MyType<?> mt2;      // no warning: type parameter given (wildcard OK!)
    }
}

यहाँ, MyType<E>एक पैरामीटर प्रकार ( JLS 4.5 ) है। आम तौर पर MyTypeसंक्षिप्त रूप में इस प्रकार को संदर्भित करना आम है , लेकिन तकनीकी रूप से यह नाम है MyType<E>

mtउपरोक्त परिभाषा में पहले बुलेट बिंदु द्वारा एक कच्चा प्रकार (और एक संकलन चेतावनी उत्पन्न करता है); innतीसरी गोली बिंदु द्वारा एक कच्चा प्रकार भी होता है।

MyType.Nestedएक पैरामीटर प्रकार नहीं है, भले ही यह एक पैरामीटर प्रकार का सदस्य है MyType<E>, क्योंकि यह है static

mt1, और mt2दोनों वास्तविक प्रकार के मापदंडों के साथ घोषित किए जाते हैं, इसलिए वे कच्चे प्रकार नहीं हैं।


कच्चे प्रकारों में ऐसा क्या खास है?

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

List names = new ArrayList(); // warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // not a compilation error!

उपरोक्त कोड ठीक चलता है, लेकिन मान लीजिए कि आपके पास निम्नलिखित भी हैं:

for (Object o : names) {
    String name = (String) o;
    System.out.println(name);
} // throws ClassCastException!
  //    java.lang.Boolean cannot be cast to java.lang.String

अब हम रन-टाइम पर परेशानी में पड़ जाते हैं, क्योंकि namesइसमें कुछ ऐसा है जो एक नहीं है instanceof String

संभवतः, यदि आप namesकेवल शामिल करना चाहते हैं, तो आप शायद अभी भी एक कच्चे प्रकार का उपयोग Stringकर सकते हैं और मैन्युअल रूप से हर add खुद की जांच कर सकते हैं , और फिर मैन्युअल रूप से Stringप्रत्येक आइटम से कास्ट कर सकते हैं namesइससे भी बेहतर , हालांकि कच्चे प्रकार का उपयोग नहीं करना है और संकलक को जावा जेनरिक की शक्ति का उपयोग करते हुए आपके लिए सभी काम करने देना चाहिए

List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!

बेशक, अगर आप करते चाहते हैं namesएक अनुमति देने के लिए Booleanहै, तो आप इसे के रूप में घोषणा कर सकते हैं List<Object> names, और इसके बाद के संस्करण कोड संकलन होगा।

यह सभी देखें


कैसे एक कच्चे प्रकार <Object>प्रकार मापदंडों के रूप में उपयोग करने से अलग है ?

निम्नलिखित प्रभावी जावा 2 संस्करण से एक उद्धरण है , आइटम 23: नए कोड में कच्चे प्रकार का उपयोग न करें :

बस कच्चे प्रकार Listऔर पैरामीटर प्रकार के बीच क्या अंतर है List<Object>? धीरे-धीरे बोलना, पूर्व ने सामान्य प्रकार की जाँच का विकल्प चुना है, जबकि बाद वाले ने संकलक को स्पष्ट रूप से बताया कि यह किसी भी प्रकार की वस्तुओं को रखने में सक्षम है। जब आप List<String>टाइप के एक पैरामीटर को पास कर सकते हैं List, तो आप इसे टाइप के एक पैरामीटर को पास नहीं कर सकते List<Object>। जेनरिक के लिए List<String>उप- नियम हैं, और कच्चे प्रकार का एक उपप्रकार है List, लेकिन पैरामीटर प्रकार का नहीं List<Object>। परिणामस्वरूप, यदि आप कच्चे प्रकार का उपयोग करते हैं List, तो आप प्रकार की सुरक्षा खो देते हैं , लेकिन यदि आप एक पैरामीटर प्रकार का उपयोग नहीं करते हैंList<Object>

बिंदु को स्पष्ट करने के लिए, निम्नलिखित विधि पर विचार करें जो एक लेता है List<Object>और एक संलग्न करता है new Object()

void appendNewObject(List<Object> list) {
   list.add(new Object());
}

जावा में जेनरिक अपरिवर्तनीय हैं। A List<String>एक नहीं है List<Object>, इसलिए निम्नलिखित एक संकलक चेतावनी उत्पन्न करेगा:

List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!

यदि आपने appendNewObjectएक कच्चे प्रकार Listको पैरामीटर के रूप में लेने की घोषणा की थी , तो यह संकलन करेगा, और इसलिए आप उस प्रकार की सुरक्षा खो देंगे जो आपको जेनरिक से मिलती है।

यह सभी देखें


कैसे एक कच्चे प्रकार <?>एक प्रकार के पैरामीटर के रूप में उपयोग करने से अलग है ?

List<Object>, List<String>आदि सभी हैं List<?>, इसलिए यह सिर्फ यह कहने के लिए लुभावना हो सकता है कि वे Listइसके बजाय हैं। हालांकि, एक बड़ा अंतर है: List<E>केवल एक परिभाषित करने के बाद से add(E), आप किसी भी मनमानी वस्तु को नहीं जोड़ सकते हैं List<?>। दूसरी ओर, चूंकि कच्चे Listप्रकार में सुरक्षा नहीं होती है, आप addबस कुछ भी कर सकते हैं List

पिछले स्निपेट की निम्नलिखित भिन्नता पर विचार करें:

static void appendNewObject(List<?> list) {
    list.add(new Object()); // compilation error!
}
//...

List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!

संकलक ने संभावित प्रकार के उल्लंघन से आपको बचाने का एक अद्भुत काम किया List<?>! यदि आपने पैरामीटर को कच्चे प्रकार के रूप में घोषित किया था List list, तो कोड संकलित होगा, और आप प्रकार के उल्लंघनकर्ता का उल्लंघन करेंगे List<String> names


एक कच्चा प्रकार उस प्रकार का क्षरण है

वापस JLS 4.8:

यह एक प्रकार के रूप में उपयोग करना संभव है विलोपन एक पैरामिट्रीकृत प्रकार या एक सरणी प्रकार जिसका तत्व प्रकार एक पैरामिट्रीकृत प्रकार है का विलोपन की। इस तरह के एक प्रकार को एक कच्चा प्रकार कहा जाता है ।

[...]

कच्चे प्रकार के सुपरक्लेसेस (क्रमशः, सुपरएन्थफेस) जेनेरिक प्रकार के किसी भी परिमाण के सुपरक्लासेस (सुपरन्टेफेसेस) के विलोपन हैं।

एक प्रकार का निर्माणकर्ता, उदाहरण विधि, या staticएक कच्चे प्रकार का गैर- क्षेत्र जो Cकि उसके सुपरक्लासेस या सुपरन्टेफ़्स से विरासत में नहीं मिला है, वह कच्चा प्रकार है जो सामान्य रूप से संबंधित घोषणा में इसके प्रकार के उन्मूलन से मेल खाता है C

सरल शब्दों में, जब एक कच्चे प्रकार का उपयोग किया जाता है, तो निर्माणकर्ता, उदाहरण के तरीके और गैर- staticफ़ील्ड भी मिट जाते हैं

निम्नलिखित उदाहरण लें:

class MyType<E> {
    List<String> getNames() {
        return Arrays.asList("John", "Mary");
    }

    public static void main(String[] args) {
        MyType rawType = new MyType();
        // unchecked warning!
        // required: List<String> found: List
        List<String> names = rawType.getNames();
        // compilation error!
        // incompatible types: Object cannot be converted to String
        for (String str : rawType.getNames())
            System.out.print(str);
    }
}

जब हम कच्चे का उपयोग MyType, getNamesसाथ ही मिट जाता है, इतना है कि यह एक कच्चे रिटर्न List!

JLS 4.6 निम्नलिखित की व्याख्या करना जारी रखता है:

टाइप इरेज़र एक कंस्ट्रक्टर या मेथड के सिग्नेचर को भी सिग्नेचर के लिए मैप करता है जिसमें कोई पैरामीटर प्रकार या वैरिएबल नहीं है। कंस्ट्रक्टर या मेथड सिग्नेचर sको मिटाना एक हस्ताक्षर है जिसमें समान नाम शामिल है sऔर सभी औपचारिक पैरामीटर प्रकारों का विलोपन s

एक विधि का वापसी प्रकार और एक सामान्य विधि या निर्माता के प्रकार के पैरामीटर भी मिटा देते हैं यदि विधि या निर्माता के हस्ताक्षर मिटा दिए जाते हैं।

जेनेरिक विधि के हस्ताक्षर के उन्मूलन में कोई प्रकार के पैरामीटर नहीं हैं।

निम्नलिखित बग रिपोर्ट में मॉरीज़ियो सिमाडामोर, एक संकलक देव और जेएलएस के लेखकों में से एक एलेक्स बकले के कुछ विचार शामिल हैं, इस तरह का व्यवहार क्यों होना चाहिए: https://bugs.openjdk.java.net/browse / JDK-6,400,189 । (संक्षेप में, यह विनिर्देशन को सरल बनाता है।)


यदि यह असुरक्षित है, तो इसे कच्चे प्रकार का उपयोग करने की अनुमति क्यों है?

यहाँ JLS 4.8 का एक और उद्धरण है:

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

प्रभावी जावा 2 संस्करण में यह जोड़ने के लिए भी है:

यह देखते हुए कि आपको कच्चे प्रकारों का उपयोग नहीं करना चाहिए, भाषा डिजाइनरों ने उन्हें अनुमति क्यों दी? अनुकूलता प्रदान करने के लिए।

जावा प्लेटफॉर्म अपने दूसरे दशक में प्रवेश करने वाला था जब जेनरिक को पेश किया गया था, और अस्तित्व में जावा कोड की एक बड़ी मात्रा थी जो जेनरिक का उपयोग नहीं करते थे। यह महत्वपूर्ण माना जाता था कि यह सभी कोड जेनेरिक का उपयोग करने वाले नए कोड के साथ कानूनी और इंटरऑपरेबल रहता है। यह सामान्य प्रकार के साथ उपयोग के लिए डिज़ाइन किए गए तरीकों के लिए मानकीकृत प्रकारों के उदाहरणों को पारित करने के लिए कानूनी होना था, और इसके विपरीत। यह आवश्यकता, जिसे माइग्रेशन कम्पैटिबिलिटी के रूप में जाना जाता है , ने कच्चे प्रकारों का समर्थन करने का निर्णय लिया।

सारांश में, नए कोड में कच्चे प्रकार का उपयोग नहीं किया जाना चाहिए। आपको हमेशा पैरामीटराइज्ड प्रकारों का उपयोग करना चाहिए


क्या कोई अपवाद नहीं हैं?

दुर्भाग्यवश, क्योंकि जावा जेनेरिक गैर-पुनरीक्षित हैं, दो अपवाद हैं जहां नए कोड में कच्चे प्रकार का उपयोग किया जाना चाहिए:

  • वर्ग शाब्दिक, उदाहरण के लिए List.class, नहींList<String>.class
  • instanceofऑपरेंड, जैसे o instanceof Set, नहींo instanceof Set<String>

यह सभी देखें


16
आपका क्या मतलब है, "जावा जेनेरिक गैर-पुनरीक्षित हैं"?
कार्ल जी

7
दूसरे अपवाद के लिए, वाक्यविन्यास o instanceof Set<?>को कच्चे प्रकार से बचने की अनुमति है (हालांकि यह इस मामले में केवल सतही है)।
पॉल बेलोरा

1
कच्चे प्रकार बहुत उपयोगी होते हैं और एक बीन के लिए जेएनडीआई लुकअप के मामले में बॉयलरप्लेट कोड को कम करते हैं जो एक इंटरफ़ेस का विस्तार करता है। यह nसमान कोड वाले प्रत्येक क्रियान्वयन वर्ग के लिए दूरस्थ सेम लिखने की आवश्यकता को हल करता है ।
djmj

8
"गैर-पुनरीक्षित" यह कहने का एक और तरीका है कि वे मिट जाते हैं। कंपाइलर जानता है कि जेनेरिक पैरामीटर क्या हैं, लेकिन यह जानकारी उत्पन्न बायोटेक पर पारित नहीं होती है। जेएलएस के लिए आवश्यक है कि कक्षा के शाब्दिक में कोई प्रकार के पैरामीटर न हों।
एरिक जी। हागस्ट्रॉम

2
@OldCurmudgeon दिलचस्प है। मेरा मतलब है कि आधिकारिक तौर पर यह न तो है , क्योंकि एक वर्ग शाब्दिक बस के रूप में परिभाषित किया गया है TypeName.class, जहां TypeNameएक सादे पहचानकर्ता ( jls ) है। काल्पनिक रूप से बोलते हुए, मुझे लगता है कि यह वास्तव में या तो हो सकता है। हो सकता है कि एक सुराग के रूप में, List<String>.classयह वैरिएंट है कि जेएलएस विशेष रूप से एक संकलक त्रुटि को कॉल करता है, इसलिए यदि वे कभी भी इसे भाषा में जोड़ते हैं तो मुझे उम्मीद होगी कि वह वही है जो वे उपयोग करते हैं।
रेडियोडफ़

62

जावा में कच्चे प्रकार क्या हैं, और मैं अक्सर क्यों सुनता हूं कि उन्हें नए कोड में उपयोग नहीं किया जाना चाहिए?

रॉ-प्रकार जावा भाषा का प्राचीन इतिहास है। शुरुआत में Collectionsवे थे और उन्होंने Objectsकुछ भी नहीं रखा और कुछ भी कम नहीं किया। वांछित प्रकार Collectionsसे आवश्यक कलाकारों पर हर ऑपरेशन Object

List aList = new ArrayList();
String s = "Hello World!";
aList.add(s);
String c = (String)aList.get(0);

जबकि इसने अधिकांश समय काम किया, त्रुटियां हुईं

List aNumberList = new ArrayList();
String one = "1";//Number one
aNumberList.add(one);
Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here

पुराने टाइपलेस संग्रह टाइप-सेफ्टी को लागू नहीं कर सकते थे इसलिए प्रोग्रामर को यह याद रखना था कि उसने एक संग्रह में क्या संग्रहीत किया है।
जेनरिक जहां इस सीमा के आसपास जाने के लिए आविष्कार किया गया था, डेवलपर संग्रहीत प्रकार को एक बार घोषित करेगा और संकलक इसके बजाय करेगा।

List<String> aNumberList = new ArrayList<String>();
aNumberList.add("one");
Integer iOne = aNumberList.get(0);//Compile time error
String sOne = aNumberList.get(0);//works fine

तुलना के लिए:

// Old style collections now known as raw types
List aList = new ArrayList(); //Could contain anything
// New style collections with Generics
List<String> aList = new ArrayList<String>(); //Contains only Strings

तुलनात्मक इंटरफ़ेस अधिक जटिल है:

//raw, not type save can compare with Other classes
class MyCompareAble implements CompareAble
{
   int id;
   public int compareTo(Object other)
   {return this.id - ((MyCompareAble)other).id;}
}
//Generic
class MyCompareAble implements CompareAble<MyCompareAble>
{
   int id;
   public int compareTo(MyCompareAble other)
   {return this.id - other.id;}
}

ध्यान दें कि कच्चे प्रकार के साथ CompareAbleइंटरफ़ेस को लागू करना असंभव है compareTo(MyCompareAble)। आपको उनका उपयोग क्यों नहीं करना चाहिए:

  • उपयोग Objectकिए जाने Collectionसे पहले किसी में संग्रहित किया जाना है
  • जेनरिक का उपयोग करने से संकलन समय की जाँच में सक्षम होता है
  • कच्चे प्रकार का उपयोग करना प्रत्येक मूल्य को संग्रहीत करने के समान है Object

कंपाइलर क्या करता है: जेनेरिक पिछड़े संगत हैं, वे उसी जावा वर्गों का उपयोग करते हैं जैसे कच्चे प्रकार करते हैं। जादू ज्यादातर संकलन के समय होता है।

List<String> someStrings = new ArrayList<String>();
someStrings.add("one");
String one = someStrings.get(0);

के रूप में संकलित किया जाएगा:

List someStrings = new ArrayList();
someStrings.add("one"); 
String one = (String)someStrings.get(0);

यह वही कोड है जो आप लिखेंगे यदि आपने सीधे कच्चे प्रकार का उपयोग किया है। सोचा कि मुझे यकीन नहीं है कि CompareAbleइंटरफ़ेस के साथ क्या होता है, मुझे लगता है कि यह दो compareToफ़ंक्शन बनाता है, एक ए MyCompareAbleऔर दूसरा एक ले रहा है और Objectइसे कास्टिंग करने के बाद पहले से गुजर रहा है।

कच्चे प्रकार के विकल्प क्या हैं: जेनेरिक का उपयोग करें


30

एक कच्चा प्रकार किसी भी प्रकार के तर्कों के बिना सामान्य वर्ग या इंटरफ़ेस का नाम है। उदाहरण के लिए, जेनेरिक बॉक्स क्लास दिया गया:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

एक पैरामीटर प्रकार बनाने के लिए Box<T>, आप औपचारिक प्रकार के पैरामीटर के लिए वास्तविक प्रकार का तर्क देते हैं T:

Box<Integer> intBox = new Box<>();

यदि वास्तविक प्रकार का तर्क छोड़ दिया जाता है, तो आप एक कच्चा प्रकार बनाते हैं Box<T>:

Box rawBox = new Box();

इसलिए, Boxसामान्य प्रकार का कच्चा प्रकार है Box<T>। हालांकि, एक गैर-सामान्य वर्ग या इंटरफ़ेस प्रकार एक कच्चा प्रकार नहीं है।

कच्चे प्रकार विरासत कोड में दिखाई देते हैं क्योंकि बहुत सारी एपीआई कक्षाएं (जैसे संग्रह कक्षाएं) जेडीके 5.0 से पहले सामान्य नहीं थीं। कच्चे प्रकारों का उपयोग करते समय, आप अनिवार्य रूप से पूर्व-जेनेरिक व्यवहार प्राप्त करते हैं - एक Boxआपको देता है Object। पिछड़ी संगतता के लिए, इसके कच्चे प्रकार के लिए एक पैरामीटर प्रकार निर्दिष्ट करने की अनुमति है:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;               // OK

लेकिन अगर आप एक कच्चे प्रकार को एक पैरामीटर प्रकार में असाइन करते हैं, तो आपको एक चेतावनी मिलती है:

Box rawBox = new Box();           // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox;     // warning: unchecked conversion

यदि आप संबंधित सामान्य प्रकार में परिभाषित जेनेरिक विधियों को लागू करने के लिए एक कच्चे प्रकार का उपयोग करते हैं तो आपको एक चेतावनी भी मिलती है:

Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8);  // warning: unchecked invocation to set(T)

चेतावनी से पता चलता है कि कच्चे प्रकार सामान्य प्रकार की जाँच को बायपास करते हैं, रनटाइम के लिए असुरक्षित कोड की पकड़ को दर्शाते हैं। इसलिए, आपको कच्चे प्रकार के उपयोग से बचना चाहिए।

टाइप एरासुरे खंड में जावा कंपाइलर कच्चे प्रकारों का उपयोग करने के बारे में अधिक जानकारी है।

अनियंत्रित त्रुटि संदेश

जैसा कि पहले उल्लेख किया गया है, जब जेनेरिक कोड के साथ विरासत कोड को मिलाते हैं, तो आपको निम्नलिखित के समान चेतावनी संदेश मिल सकते हैं:

नोट: Example.java अनियंत्रित या असुरक्षित संचालन का उपयोग करता है।

ध्यान दें: -लगाना के साथ पुनरावर्ती: विवरण के लिए अनियंत्रित।

यह पुराने API का उपयोग करते समय हो सकता है जो कच्चे प्रकारों पर काम करता है, जैसा कि निम्नलिखित उदाहरण में दिखाया गया है:

public class WarningDemo {
    public static void main(String[] args){
        Box<Integer> bi;
        bi = createBox();
    }

    static Box createBox(){
        return new Box();
    }
}

शब्द "अनियंत्रित" का मतलब है कि संकलक के पास पर्याप्त प्रकार की जानकारी नहीं है ताकि वह सभी प्रकार की जाँच कर सके ताकि प्रकार की सुरक्षा सुनिश्चित हो सके। डिफ़ॉल्ट रूप से "अनियंत्रित" चेतावनी अक्षम है, हालांकि संकलक एक संकेत देता है। सभी "अनियंत्रित" चेतावनियों को देखने के लिए, -Xlint के साथ recompile: अनियंत्रित।

पिछले उदाहरण को पुनः प्राप्त करना -Xlint के साथ: अनियंत्रित निम्नलिखित अतिरिक्त जानकारी का खुलासा करता है:

WarningDemo.java:4: warning: [unchecked] unchecked conversion
found   : Box
required: Box<java.lang.Integer>
        bi = createBox();
                      ^
1 warning

अनियंत्रित चेतावनियों को पूरी तरह से अक्षम करने के लिए, -Xlint: -unchecked ध्वज का उपयोग करें। @SuppressWarnings("unchecked")एनोटेशन अनियंत्रित चेतावनी को रोकता है। यदि आप @SuppressWarningsवाक्य रचना से अपरिचित हैं , तो एनोटेशन देखें।

मूल स्रोत: जावा ट्यूटोरियल


21

जावा में एक "कच्चा" प्रकार एक वर्ग है जो गैर-जेनेरिक है और "रॉ" ऑब्जेक्ट्स के साथ व्यवहार करता है, न कि टाइप-सुरक्षित जेनेरिक प्रकार के मापदंडों से।

उदाहरण के लिए, जावा जेनरिक उपलब्ध होने से पहले, आप इस तरह एक संग्रह वर्ग का उपयोग करेंगे:

LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);

जब आप सूची में अपना ऑब्जेक्ट जोड़ते हैं, तो यह परवाह नहीं करता है कि यह किस प्रकार की वस्तु है, और जब आप इसे सूची से प्राप्त करते हैं, तो आपको इसे स्पष्ट रूप से उस प्रकार में डालना होगा जिसकी आप अपेक्षा कर रहे हैं।

जेनरिक का उपयोग करते हुए, आप "अज्ञात" कारक को हटा देते हैं, क्योंकि आपको स्पष्ट रूप से निर्दिष्ट करना चाहिए कि किस प्रकार की वस्तुएं सूची में जा सकती हैं:

LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);

ध्यान दें कि जेनेरिक के साथ आपको कॉल से आने वाली वस्तु को नहीं डालना है, संग्रह को केवल MyObject के साथ काम करने के लिए परिभाषित किया गया है। यह बहुत तथ्य जेनरिक के लिए मुख्य ड्राइविंग कारक है। यह कुछ समय में रनटाइम त्रुटियों के स्रोत को बदलता है जिसे संकलन समय पर जांचा जा सकता है।


3
अधिक विशेष रूप से, एक कच्चा प्रकार वह है जो आपको मिलता है जब आप सामान्य प्रकार के लिए बस प्रकार के मापदंडों को छोड़ देते हैं। कच्चे प्रकार वास्तव में कभी केवल एक बैकवर्ड-संगतता सुविधा थे, और संभवतः हटाने के अधीन हैं। आप समान व्यवहार का उपयोग करके प्राप्त कर सकते हैं? वाइल्डकार्ड मापदंडों।
जॉन फ्लैटनेस

@ एक्सोक्रेट: समान लेकिन अलग! का उपयोग कर ?अभी भी प्रकार सुरक्षा प्रदान करता है। मैंने अपने उत्तर में इसे कवर किया।
पॉलीजेन लुब्रिकेंट

19
 private static List<String> list = new ArrayList<String>();

आपको टाइप-पैरामीटर निर्दिष्ट करना चाहिए।

चेतावनी सलाह देती है कि जिन प्रकारों को जेनेरिक के समर्थन के लिए परिभाषित किया गया है , उन्हें उनके कच्चे रूप का उपयोग करने के बजाय, मानकीकृत किया जाना चाहिए।

Listजेनरिक का समर्थन करने के लिए परिभाषित किया गया है public class List<E>:। यह कई प्रकार-सुरक्षित संचालन की अनुमति देता है, जो कि संकलन-समय की जाँच की जाती है।


3
अब जावा 7 में हीरे की खोज द्वारा प्रतिस्थापित -private static List<String> list = new ArrayList<>();
इयान कैंपबेल

14

एक कच्चा प्रकार क्या है और मैं अक्सर क्यों सुनता हूं कि उन्हें नए कोड में उपयोग नहीं किया जाना चाहिए?

एक "रॉ टाइप" एक जेनेरिक क्लास का उपयोग है, जो इसके पैरामीटर प्रकार (एस) के लिए एक प्रकार के तर्क (एस) को निर्दिष्ट किए बिना, जैसे कि Listइसके बजाय का उपयोग कर रहा है List<String>। जब जेनेरिक को जावा में पेश किया गया था, तो जेनेरिक का उपयोग करने के लिए कई वर्गों को अपडेट किया गया था। इन वर्गों को "कच्चे प्रकार" (एक प्रकार के तर्क को निर्दिष्ट किए बिना) का उपयोग करके विरासत कोड को अभी भी संकलित करने की अनुमति दी।

"कच्चे प्रकार" का उपयोग पीछे की संगतता के लिए किया जाता है। नए कोड में उनके उपयोग की अनुशंसा नहीं की जाती है क्योंकि एक प्रकार के तर्क के साथ सामान्य वर्ग का उपयोग करने से मजबूत टाइपिंग की अनुमति मिलती है, जिससे कोड समझ में सुधार हो सकता है और पहले संभावित समस्याओं को पकड़ सकता है।

यदि हम कच्चे प्रकारों का उपयोग नहीं कर सकते हैं, और यह कैसे बेहतर है?

एक उपयुक्त प्रकार के तर्क (जैसे List<String>) के साथ, इच्छित विकल्प जेनेरिक कक्षाओं का उपयोग करना है । यह प्रोग्रामर को विशेष रूप से प्रकारों को निर्दिष्ट करने की अनुमति देता है, एक चर या डेटा संरचना के इच्छित उपयोग के बारे में भविष्य के रखरखाव के लिए अधिक अर्थ बताता है, और यह संकलक को बेहतर प्रकार-सुरक्षा लागू करने की अनुमति देता है। ये फायदे मिलकर कोड की गुणवत्ता में सुधार कर सकते हैं और कुछ कोडिंग त्रुटियों की शुरूआत को रोकने में मदद कर सकते हैं।

उदाहरण के लिए, एक विधि के लिए जहां प्रोग्रामर सूची नामों को सुनिश्चित करना चाहता है जिसे 'नाम' कहा जाता है जिसमें केवल स्ट्रिंग्स शामिल हैं:

List<String> names = new ArrayList<String>();
names.add("John");          // OK
names.add(new Integer(1));  // compile error

1
आह, तो मेरे अपने जवाब में stackoverflow.com/questions/2770111/…polygenelubricants से "कच्चे प्रकार" संदर्भों की नकल करने का प्रलोभन दिया, लेकिन मुझे लगता है कि मैं उन्हें अपने जवाब में उपयोग के लिए छोड़ दूंगा।
बर्ट F

1
हां, मैं अनिवार्य रूप से उस सेगमेंट को कॉपी-एंड-पेस्ट कर रहा हूं, जहां हर जगह लोग स्टैकओवरफ्लो पर कच्चे प्रकार का उपयोग करते हैं, और अंत में अभी से संदर्भित करने के लिए सिर्फ एक प्रश्न का फैसला किया है। मुझे उम्मीद है कि यह समुदाय के लिए एक अच्छा योगदान है।
पॉलीजेन लुब्रिकेंट

1
@ पॉली आक्सीजन लूब्रिकेंट पर मैंने गौर किया - हमने कुछ ऐसे ही सवालों को मारा :-)
बर्ट एफ

1
@ ha9u63ar: दरअसल। सामान्य तौर पर संक्षिप्त और सरल उत्तर कम से कम लंबे और स्वीकृत लोगों के समान ही अच्छे होते हैं।
DISPLAYNAME

"मजबूत साइडिंग" क्या है?
carloswm85

12

संकलक आपको यह लिखना चाहता है:

private static List<String> list = new ArrayList<String>();

क्योंकि अन्यथा, आप किसी भी प्रकार को जोड़ सकते हैं list, जिससे तात्कालिकता new ArrayList<String>()व्यर्थ हो जाती है। जावा जेनरिक केवल एक संकलन-समय की विशेषता है, इसलिए किसी ऑब्जेक्ट को "कच्चे प्रकार" के संदर्भ में असाइन किए जाने पर new ArrayList<String>()खुशी से स्वीकार किया जाएगा Integerया JFrameतत्व List- ऑब्जेक्ट स्वयं ही कुछ भी नहीं जानता है कि यह किस प्रकार का होना चाहिए, केवल कंपाइलर करता है।


12

यहां मैं कई मामलों पर विचार कर रहा हूं जिनके माध्यम से आप अवधारणा को स्पष्ट कर सकते हैं

1. ArrayList<String> arr = new ArrayList<String>();
2. ArrayList<String> arr = new ArrayList();
3. ArrayList arr = new ArrayList<String>();

मामला एक

ArrayList<String> arrयह ArrayListप्रकार के साथ एक संदर्भ चर है Stringजो प्रकार के ArralyListऑब्जेक्ट के संदर्भ में है String। इसका मतलब है कि यह केवल स्ट्रिंग प्रकार ऑब्जेक्ट को पकड़ सकता है।

यह Stringरॉ टाइप नहीं करने के लिए एक स्ट्रिक्ट है , इसलिए यह कभी भी चेतावनी नहीं देगा।

    arr.add("hello");// alone statement will compile successfully and no warning.

    arr.add(23);  //prone to compile time error.
     //error: no suitable method found for add(int)

केस 2

इस मामले ArrayList<String> arrमें एक सख्त प्रकार है लेकिन आपका ऑब्जेक्ट new ArrayList();एक कच्चा प्रकार है।

    arr.add("hello"); //alone this compile but raise the warning.
    arr.add(23);  //again prone to compile time error.
    //error: no suitable method found for add(int)

यहाँ arrएक सख्त प्रकार है। इसलिए, यह संकलन समय त्रुटि को जोड़ देगा integer

चेतावनी : - एक Rawप्रकार की वस्तु को संदर्भित Strictप्रकार के संदर्भ में संदर्भित किया जाता है ArrayList

केस 3

इस मामले ArrayList arrमें एक कच्चा प्रकार है, लेकिन आपका ऑब्जेक्ट new ArrayList<String>();एक सख्त प्रकार है।

    arr.add("hello");  
    arr.add(23);  //compiles fine but raise the warning.

यह किसी भी प्रकार के ऑब्जेक्ट को इसमें जोड़ेगा क्योंकि arrयह एक रॉ टाइप है।

चेतावनी : - एक Strictप्रकार वस्तु को संदर्भित rawप्रकार के लिए संदर्भित किया जाता है।


8

एक कच्चा- प्रकार एक सामान्य प्रकार का उपयोग करते समय एक प्रकार के पैरामीटर की कमी है ।

कच्चे प्रकार है क्योंकि यह हो सकता है एक डालने की तरह है, क्रम त्रुटियों का कारण नहीं किया जाना चाहिए doubleजो एक होना चाहिए था में Setकी intहै।

Set set = new HashSet();
set.add(3.45); //ok

से सामान Setनिकालते समय, आप नहीं जानते कि क्या निकल रहा है। मान लेते हैं कि आप यह उम्मीद करते हैं कि यह सब हो int, आप इसे कर रहे हैं Integer; double3.45 के साथ आने पर रनटाइम पर अपवाद ।

आपके साथ जोड़े गए एक प्रकार के पैरामीटर के साथ Set, आपको एक बार में एक संकलन त्रुटि मिलेगी। यह प्रीमेप्टिव एरर आपको रनटाइम के दौरान कुछ ब्लो करने से पहले समस्या को ठीक करने देता है (इस प्रकार समय और प्रयास की बचत)।

Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.

7

यहां एक और मामला है जहां कच्चे प्रकार आपको काटेंगे:

public class StrangeClass<T> {
  @SuppressWarnings("unchecked")
  public <X> X getSomethingElse() {
    return (X)"Testing something else!";
  }

  public static void main(String[] args) {
    final StrangeClass<String> withGeneric    = new StrangeClass<>();
    final StrangeClass         withoutGeneric = new StrangeClass();
    final String               value1,
                               value2;

    // Compiles
    value1 = withGeneric.getSomethingElse();

    // Produces compile error:
    // incompatible types: java.lang.Object cannot be converted to java.lang.String
    value2 = withoutGeneric.getSomethingElse();
  }
}

जैसा कि स्वीकृत उत्तर में उल्लेख किया गया है, आप कच्चे प्रकार के कोड के भीतर जेनेरिक के लिए सभी समर्थन खो देते हैं। हर प्रकार के पैरामीटर को उसके विलोपन में बदल दिया जाता है (जो उपरोक्त उदाहरण में बस है Object)।


5

क्या कह रहा है कि आपकी listएक Listअप्रतिबंधित वस्तु है। वह यह है कि जावा को यह नहीं पता है कि सूची के अंदर किस तरह की वस्तुएं हैं। फिर जब आप उस सूची को पुनरावृत्त करना चाहते हैं, तो आपको प्रत्येक तत्व को डालना होगा, उस तत्व के गुणों (इस मामले में, स्ट्रिंग) तक पहुंचने में सक्षम होने के लिए।

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

private static List<String> list = new ArrayList<String>();

4

ट्यूटोरियल पृष्ठ

एक कच्चा प्रकार किसी भी प्रकार के तर्कों के बिना सामान्य वर्ग या इंटरफ़ेस का नाम है। उदाहरण के लिए, जेनेरिक बॉक्स क्लास दिया गया:

public class Box<T> {
    public void set(T t) { /* ... */ }
    // ...
}

एक प्रकार का बॉक्स बनाने के लिए, आप औपचारिक प्रकार के पैरामीटर T के लिए वास्तविक प्रकार का तर्क देते हैं:

Box<Integer> intBox = new Box<>();

यदि वास्तविक प्रकार का तर्क छोड़ दिया जाता है, तो आप एक कच्चे प्रकार का बॉक्स बनाते हैं:

Box rawBox = new Box();

2

कच्चे प्रकार से बचें

कच्चे प्रकार एक प्रकार के पैरामीटर को निर्दिष्ट किए बिना सामान्य प्रकार का उपयोग करने का संदर्भ देते हैं।

उदाहरण के लिए ,

एक सूची एक कच्चा प्रकार है, जबकि List<String>एक पैरामीटर प्रकार है।

जब JDK 1.5 में जेनेरिक को पेश किया गया था, तो जावा के पुराने संस्करणों के साथ केवल पश्चगामी संगतता बनाए रखने के लिए कच्चे प्रकार को बरकरार रखा गया था। हालांकि कच्चे प्रकार का उपयोग करना अभी भी संभव है,

उन्हें टाला जाना चाहिए :

  • उन्हें आमतौर पर जातियों की आवश्यकता होती है
  • वे सुरक्षित नहीं हैं, और कुछ महत्वपूर्ण प्रकार की त्रुटियां केवल रनटाइम पर दिखाई देंगी
  • वे कम अभिव्यंजक हैं, और उसी तरह से स्व-दस्तावेज नहीं है जैसे कि मानकीकृत प्रकार उदाहरण

    import java.util.*;
    
    public final class AvoidRawTypes {
    
    void withRawType() {
    
        //Raw List doesn't self-document, 
        //doesn't state explicitly what it can contain
    
        List stars = Arrays.asList("Arcturus", "Vega", "Altair");
    
        Iterator iter = stars.iterator();
    
        while (iter.hasNext()) {
    
            String star = (String) iter.next(); //cast needed
    
            log(star);
        }
    
    }
    
    void withParameterizedType() {
    
        List < String > stars = Arrays.asList("Spica", "Regulus", "Antares");
    
        for (String star: stars) {
    
            log(star);
        }
    
    }
    
    private void log(Object message) {
    
        System.out.println(Objects.toString(message));
    
    }
    
    }

संदर्भ के लिए : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html


1

मैंने कुछ नमूना अभ्यास करने और ठीक उसी पहेली के होने के बाद यह पृष्ठ पाया।

============== मैं इस कोड से नमूना ============= द्वारा प्रदान किया गया

public static void main(String[] args) throws IOException {

    Map wordMap = new HashMap();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator i = wordMap.entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Map.Entry) i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

====================== इस कोड के लिए ========================

public static void main(String[] args) throws IOException {
    // replace with TreeMap to get them sorted by name
    Map<String, Integer> wordMap = new HashMap<String, Integer>();
    if (args.length > 0) {
        for (int i = 0; i < args.length; i++) {
            countWord(wordMap, args[i]);
        }
    } else {
        getWordFrequency(System.in, wordMap);
    }
    for (Iterator<Entry<String, Integer>> i = wordMap.entrySet().iterator(); i.hasNext();) {
        Entry<String, Integer> entry =   i.next();
        System.out.println(entry.getKey() + " :\t" + entry.getValue());
    }

}

================================================== =============================

यह सुरक्षित हो सकता है लेकिन दर्शन को ध्वस्त करने में 4 घंटे लगे ...


0

कच्चे प्रकार ठीक हैं जब वे व्यक्त करते हैं जो आप व्यक्त करना चाहते हैं।

उदाहरण के लिए, एक deserialisation फ़ंक्शन एक लौट सकता है List, लेकिन यह सूची के तत्व प्रकार को नहीं जानता है। तो Listयहाँ उचित वापसी प्रकार है।


आप उपयोग कर सकते हैं ? प्रकार पैरामीटर के रूप में
डेनियल किस

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