प्रशन:
- जावा में कच्चे प्रकार क्या हैं, और मैं अक्सर क्यों सुनता हूं कि उन्हें नए कोड में उपयोग नहीं किया जाना चाहिए?
- यदि हम कच्चे प्रकारों का उपयोग नहीं कर सकते हैं, और यह कैसे बेहतर है?
जवाबों:
जावा भाषा विनिर्देश एक कच्चे प्रकार को परिभाषित करता है:
कच्चे प्रकार को निम्नलिखित में से एक के रूप में परिभाषित किया गया है:
संदर्भ प्रकार जो एक सामान्य प्रकार की घोषणा के साथ एक बिना किसी प्रकार के तर्क सूची के नाम से बनता है।
एक सरणी प्रकार जिसका तत्व प्रकार एक कच्चा प्रकार है।
एक
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>
o instanceof Set<?>
को कच्चे प्रकार से बचने की अनुमति है (हालांकि यह इस मामले में केवल सतही है)।
n
समान कोड वाले प्रत्येक क्रियान्वयन वर्ग के लिए दूरस्थ सेम लिखने की आवश्यकता को हल करता है ।
TypeName.class
, जहां TypeName
एक सादे पहचानकर्ता ( jls ) है। काल्पनिक रूप से बोलते हुए, मुझे लगता है कि यह वास्तव में या तो हो सकता है। हो सकता है कि एक सुराग के रूप में, List<String>.class
यह वैरिएंट है कि जेएलएस विशेष रूप से एक संकलक त्रुटि को कॉल करता है, इसलिए यदि वे कभी भी इसे भाषा में जोड़ते हैं तो मुझे उम्मीद होगी कि वह वही है जो वे उपयोग करते हैं।
जावा में कच्चे प्रकार क्या हैं, और मैं अक्सर क्यों सुनता हूं कि उन्हें नए कोड में उपयोग नहीं किया जाना चाहिए?
रॉ-प्रकार जावा भाषा का प्राचीन इतिहास है। शुरुआत में 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
इसे कास्टिंग करने के बाद पहले से गुजर रहा है।
कच्चे प्रकार के विकल्प क्या हैं: जेनेरिक का उपयोग करें
एक कच्चा प्रकार किसी भी प्रकार के तर्कों के बिना सामान्य वर्ग या इंटरफ़ेस का नाम है। उदाहरण के लिए, जेनेरिक बॉक्स क्लास दिया गया:
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
वाक्य रचना से अपरिचित हैं , तो एनोटेशन देखें।
मूल स्रोत: जावा ट्यूटोरियल
जावा में एक "कच्चा" प्रकार एक वर्ग है जो गैर-जेनेरिक है और "रॉ" ऑब्जेक्ट्स के साथ व्यवहार करता है, न कि टाइप-सुरक्षित जेनेरिक प्रकार के मापदंडों से।
उदाहरण के लिए, जावा जेनरिक उपलब्ध होने से पहले, आप इस तरह एक संग्रह वर्ग का उपयोग करेंगे:
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 के साथ काम करने के लिए परिभाषित किया गया है। यह बहुत तथ्य जेनरिक के लिए मुख्य ड्राइविंग कारक है। यह कुछ समय में रनटाइम त्रुटियों के स्रोत को बदलता है जिसे संकलन समय पर जांचा जा सकता है।
?
अभी भी प्रकार सुरक्षा प्रदान करता है। मैंने अपने उत्तर में इसे कवर किया।
private static List<String> list = new ArrayList<String>();
आपको टाइप-पैरामीटर निर्दिष्ट करना चाहिए।
चेतावनी सलाह देती है कि जिन प्रकारों को जेनेरिक के समर्थन के लिए परिभाषित किया गया है , उन्हें उनके कच्चे रूप का उपयोग करने के बजाय, मानकीकृत किया जाना चाहिए।
List
जेनरिक का समर्थन करने के लिए परिभाषित किया गया है public class List<E>
:। यह कई प्रकार-सुरक्षित संचालन की अनुमति देता है, जो कि संकलन-समय की जाँच की जाती है।
private static List<String> list = new ArrayList<>();
एक कच्चा प्रकार क्या है और मैं अक्सर क्यों सुनता हूं कि उन्हें नए कोड में उपयोग नहीं किया जाना चाहिए?
एक "रॉ टाइप" एक जेनेरिक क्लास का उपयोग है, जो इसके पैरामीटर प्रकार (एस) के लिए एक प्रकार के तर्क (एस) को निर्दिष्ट किए बिना, जैसे कि List
इसके बजाय का उपयोग कर रहा है List<String>
। जब जेनेरिक को जावा में पेश किया गया था, तो जेनेरिक का उपयोग करने के लिए कई वर्गों को अपडेट किया गया था। इन वर्गों को "कच्चे प्रकार" (एक प्रकार के तर्क को निर्दिष्ट किए बिना) का उपयोग करके विरासत कोड को अभी भी संकलित करने की अनुमति दी।
"कच्चे प्रकार" का उपयोग पीछे की संगतता के लिए किया जाता है। नए कोड में उनके उपयोग की अनुशंसा नहीं की जाती है क्योंकि एक प्रकार के तर्क के साथ सामान्य वर्ग का उपयोग करने से मजबूत टाइपिंग की अनुमति मिलती है, जिससे कोड समझ में सुधार हो सकता है और पहले संभावित समस्याओं को पकड़ सकता है।
यदि हम कच्चे प्रकारों का उपयोग नहीं कर सकते हैं, और यह कैसे बेहतर है?
एक उपयुक्त प्रकार के तर्क (जैसे List<String>
) के साथ, इच्छित विकल्प जेनेरिक कक्षाओं का उपयोग करना है । यह प्रोग्रामर को विशेष रूप से प्रकारों को निर्दिष्ट करने की अनुमति देता है, एक चर या डेटा संरचना के इच्छित उपयोग के बारे में भविष्य के रखरखाव के लिए अधिक अर्थ बताता है, और यह संकलक को बेहतर प्रकार-सुरक्षा लागू करने की अनुमति देता है। ये फायदे मिलकर कोड की गुणवत्ता में सुधार कर सकते हैं और कुछ कोडिंग त्रुटियों की शुरूआत को रोकने में मदद कर सकते हैं।
उदाहरण के लिए, एक विधि के लिए जहां प्रोग्रामर सूची नामों को सुनिश्चित करना चाहता है जिसे 'नाम' कहा जाता है जिसमें केवल स्ट्रिंग्स शामिल हैं:
List<String> names = new ArrayList<String>();
names.add("John"); // OK
names.add(new Integer(1)); // compile error
polygenelubricants
से "कच्चे प्रकार" संदर्भों की नकल करने का प्रलोभन दिया, लेकिन मुझे लगता है कि मैं उन्हें अपने जवाब में उपयोग के लिए छोड़ दूंगा।
संकलक आपको यह लिखना चाहता है:
private static List<String> list = new ArrayList<String>();
क्योंकि अन्यथा, आप किसी भी प्रकार को जोड़ सकते हैं list
, जिससे तात्कालिकता new ArrayList<String>()
व्यर्थ हो जाती है। जावा जेनरिक केवल एक संकलन-समय की विशेषता है, इसलिए किसी ऑब्जेक्ट को "कच्चे प्रकार" के संदर्भ में असाइन किए जाने पर new ArrayList<String>()
खुशी से स्वीकार किया जाएगा Integer
या JFrame
तत्व List
- ऑब्जेक्ट स्वयं ही कुछ भी नहीं जानता है कि यह किस प्रकार का होना चाहिए, केवल कंपाइलर करता है।
यहां मैं कई मामलों पर विचार कर रहा हूं जिनके माध्यम से आप अवधारणा को स्पष्ट कर सकते हैं
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)
इस मामले 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
।
इस मामले ArrayList arr
में एक कच्चा प्रकार है, लेकिन आपका ऑब्जेक्ट new ArrayList<String>();
एक सख्त प्रकार है।
arr.add("hello");
arr.add(23); //compiles fine but raise the warning.
यह किसी भी प्रकार के ऑब्जेक्ट को इसमें जोड़ेगा क्योंकि arr
यह एक रॉ टाइप है।
चेतावनी : - एक
Strict
प्रकार वस्तु को संदर्भितraw
प्रकार के लिए संदर्भित किया जाता है।
एक कच्चा- प्रकार एक सामान्य प्रकार का उपयोग करते समय एक प्रकार के पैरामीटर की कमी है ।
कच्चे प्रकार है क्योंकि यह हो सकता है एक डालने की तरह है, क्रम त्रुटियों का कारण नहीं किया जाना चाहिए double
जो एक होना चाहिए था में Set
की int
है।
Set set = new HashSet();
set.add(3.45); //ok
से सामान Set
निकालते समय, आप नहीं जानते कि क्या निकल रहा है। मान लेते हैं कि आप यह उम्मीद करते हैं कि यह सब हो int
, आप इसे कर रहे हैं Integer
; double
3.45 के साथ आने पर रनटाइम पर अपवाद ।
आपके साथ जोड़े गए एक प्रकार के पैरामीटर के साथ Set
, आपको एक बार में एक संकलन त्रुटि मिलेगी। यह प्रीमेप्टिव एरर आपको रनटाइम के दौरान कुछ ब्लो करने से पहले समस्या को ठीक करने देता है (इस प्रकार समय और प्रयास की बचत)।
Set<Integer> set = new HashSet<Integer>();
set.add(3.45); //NOT ok.
यहां एक और मामला है जहां कच्चे प्रकार आपको काटेंगे:
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
)।
क्या कह रहा है कि आपकी list
एक List
अप्रतिबंधित वस्तु है। वह यह है कि जावा को यह नहीं पता है कि सूची के अंदर किस तरह की वस्तुएं हैं। फिर जब आप उस सूची को पुनरावृत्त करना चाहते हैं, तो आपको प्रत्येक तत्व को डालना होगा, उस तत्व के गुणों (इस मामले में, स्ट्रिंग) तक पहुंचने में सक्षम होने के लिए।
आम तौर पर संग्रह को बेहतर बनाने के लिए एक बेहतर विचार है, इसलिए आपको रूपांतरण की समस्या नहीं है, आप केवल पैरामीरिज़्ड प्रकार के तत्वों को जोड़ पाएंगे और आपका संपादक आपको चयन करने के लिए उचित तरीकों की पेशकश करेगा।
private static List<String> list = new ArrayList<String>();
एक कच्चा प्रकार किसी भी प्रकार के तर्कों के बिना सामान्य वर्ग या इंटरफ़ेस का नाम है। उदाहरण के लिए, जेनेरिक बॉक्स क्लास दिया गया:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
एक प्रकार का बॉक्स बनाने के लिए, आप औपचारिक प्रकार के पैरामीटर T के लिए वास्तविक प्रकार का तर्क देते हैं:
Box<Integer> intBox = new Box<>();
यदि वास्तविक प्रकार का तर्क छोड़ दिया जाता है, तो आप एक कच्चे प्रकार का बॉक्स बनाते हैं:
Box rawBox = new Box();
कच्चे प्रकार से बचें
कच्चे प्रकार एक प्रकार के पैरामीटर को निर्दिष्ट किए बिना सामान्य प्रकार का उपयोग करने का संदर्भ देते हैं।
उदाहरण के लिए ,
एक सूची एक कच्चा प्रकार है, जबकि 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
मैंने कुछ नमूना अभ्यास करने और ठीक उसी पहेली के होने के बाद यह पृष्ठ पाया।
============== मैं इस कोड से नमूना ============= द्वारा प्रदान किया गया
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 घंटे लगे ...
कच्चे प्रकार ठीक हैं जब वे व्यक्त करते हैं जो आप व्यक्त करना चाहते हैं।
उदाहरण के लिए, एक deserialisation फ़ंक्शन एक लौट सकता है List
, लेकिन यह सूची के तत्व प्रकार को नहीं जानता है। तो List
यहाँ उचित वापसी प्रकार है।