एक सरणी Iterable के लिए असाइन करने योग्य क्यों नहीं है?


186

Java5 के साथ हम लिख सकते हैं:

Foo[] foos = ...
for (Foo foo : foos) 

या सिर्फ लूप के लिए Iterable का उपयोग करना। यह बहुत आसान है।

हालाँकि आप इस तरह से चलने के लिए एक सामान्य विधि नहीं लिख सकते हैं:

public void bar(Iterable<Foo> foos) { .. }

और एक सरणी के साथ इसे कॉल करना क्योंकि यह एक Iterable नहीं है:

Foo[] foos = { .. };
bar(foos);  // compile time error 

मैं इस डिजाइन निर्णय के पीछे के कारणों के बारे में सोच रहा हूं।


8
Arrays.asList काफी अच्छा है मुझे लगता है
dfa

17
यह एक दार्शनिक सवाल है
dfa

2
जावा 5+ में सरणियों से निपटने का एक अच्छा कारण है, वैरगेज तरीके।
जेफ वॉकर

2
@ टोरेंट: सच है, लेकिन अगर आप इसे एक ऐसी विधि से पारित कर रहे हैं, जो एक Iterable को स्वीकार करता है, तो आप संभवतः वैसे भी कोई बदलाव नहीं कर रहे हैं।
माइकल मायर्स

5
वास्तव में, Arrays.asList पर्याप्त नहीं है क्योंकि यह आदिम प्रकारों के सरणियों पर काम नहीं करता है। आदिम प्रकार के मूल रूप से पुनरावृति (बॉक्सिंग) तत्वों का एकमात्र अंतर्निहित तरीका प्रतिबिंब, उपयोग के साथ है java.lang.reflect.Array, लेकिन इसका प्रदर्शन कमजोर है। हालाँकि, यदि आप चाहें तो आदिम प्रकार के सरणियों को लपेटने के लिए आप अपने स्वयं के पुनरावृत्तियों (या सूची कार्यान्वयन!) को लिख सकते हैं।
बोएन

जवाबों:


78

सरणियाँ इंटरफेस ( Cloneableऔर java.io.Serializable) को लागू कर सकती हैं । तो क्यों नहीं Iterable? मुझे लगता है कि Iterableबलों को एक iteratorविधि जोड़ना है , और सरणियाँ तरीकों को लागू नहीं करती हैं। char[]ओवरराइड भी नहीं करता है toString। वैसे भी, संदर्भों के सरणियों को आदर्श से कम माना जाना चाहिए - Listएस का उपयोग करें । Dfa टिप्पणियों के रूप में, Arrays.asListआपके लिए रूपांतरण, स्पष्ट रूप से करेगा।

(कहा जाता है कि, आप cloneसरणियों पर कॉल कर सकते हैं।)


23
> "... और सरणियाँ विधियों को लागू नहीं करती हैं।" मुझे लगता है कि यह एक और दार्शनिक सवाल है; सरणियाँ कभी भी आदिम प्रकार नहीं थीं, और जावा दर्शन पढ़ता है कि "सब कुछ एक वस्तु है (आदिम प्रकार को छोड़कर)"। फिर भी, सरणियाँ विधियों को लागू नहीं करती हैं, भले ही एक गज़िलियन ऑपरेशन हो जो शुरू से ही एक सरणी का उपयोग करना चाहते हैं। ओह, यह सही है, जेनेरिक के एक खेद के रूप में आने से पहले सरणियाँ केवल दृढ़ता से टाइप किए गए संग्रह थे।
फतुहोकू 12

2
यदि आपको किसी सरणी में डेटा मिला है, तो संभव है कि आप निम्न-स्तरीय प्रदर्शन कर रहे हों, प्रदर्शन महत्वपूर्ण कार्य जैसे कि बाइट से पढ़ना [] धाराओं से पढ़ा जाता है। नीचे दिए गए @ तर्क के रूप में, टाइप करने के लिए असमर्थता संभवतया जावा जेनेरिकों से उपजी है जो प्राथमिकताओं का समर्थन नहीं कर रहे हैं।
ड्रू नोक

2
@FatuHoku जेनरिक का सुझाव देते हुए खेद था कि एक गलत दृष्टिकोण गलत है। जेनेरिक की वांछनीयता को हमेशा सराहा गया। Arrays आदिम नहीं हैं (मैंने नहीं कहा कि वे थे), लेकिन वे निम्न स्तर के हैं। एक चीज जिसे आप सरणियों के साथ करना चाहते हैं, उनका उपयोग वेक्टर जैसी संरचनाओं के कार्यान्वयन विवरण के रूप में किया जाता है।
टॉम हॉल्टिन - 14

1
Iterator<T>भी आवश्यकता है remove(T), हालांकि यह एक फेंक करने के लिए अनुमति दी है UnsupportedOperationException
वचर्जिन

Arrays तरीके लागू करते हैं: वे सभी तरीकों को लागू करते हैं java.lang.Object
मुहस्तिथ

59

सरणी एक वस्तु है, लेकिन इसके आइटम नहीं हो सकते हैं। सरणी int की तरह एक आदिम प्रकार धारण कर सकती है, जिसे Iterable सामना नहीं कर सकता है। कम से कम मैं यही मानता हूं।


3
इसका मतलब है कि Iterableइंटरफ़ेस का समर्थन करने के लिए, आवरण कक्षाओं का उपयोग करने के लिए आदिम सरणियों को विशेष होना चाहिए। इनमें से कोई भी वास्तव में एक बड़ी बात नहीं है, क्योंकि प्रकार के पैरामीटर वैसे भी सभी नकली हैं।
thejoshwolfe

8
यह ऑब्जेक्ट सरणियों को Iterable को लागू करने से नहीं रोकेगा। यह भी आदिम सरणियों को लिपटे प्रकार के लिए Iterable को लागू करने से नहीं रोकेगा।
बोअन '

1
ऑटोबॉक्सिंग इसे संभाल सकता है
टिम ब्यूट

मुझे लगता है कि यह सही कारण है। यह आदिम प्रकारों के सरणियों के लिए संतोषजनक काम नहीं करेगा, जब तक कि जेनरिक आदिम प्रकारों (जैसे के List<int>बजाय List<Integer>, आदि) का समर्थन करते हैं । एक हैक रैपर के साथ किया जा सकता है, लेकिन एक प्रदर्शन हानि पर - और अधिक महत्वपूर्ण बात - अगर यह हैक किया गया था, तो यह भविष्य में जावा में इसे ठीक से लागू करने से रोकता है (उदाहरण के int[].iterator()लिए हमेशा के Iterator<Integer>बजाय लौटने के लिए लॉक हो जाएगा Iterator<int>)। शायद, जावा (प्रोजेक्ट वल्लाह) के लिए आगामी मूल्य-प्रकार + जेनेरिक-विशेषज्ञता एरे को लागू कर देगा Iterable
बजरके

16

Arrays को समर्थन करना चाहिए Iterable, वे सिर्फ उसी कारण से नहीं करते हैं। .NET सरणियाँ किसी ऐसे इंटरफ़ेस का समर्थन नहीं करती हैं जो स्थिति के अनुसार आसानी से यादृच्छिक अभिगम की अनुमति देता है (मानक के रूप में परिभाषित ऐसा कोई इंटरफ़ेस नहीं है)। मूल रूप से, फ्रेमवर्क में अक्सर छोटे अंतराल होते हैं, जिन्हें ठीक करने के लिए किसी के समय की आवश्यकता नहीं होती है। इससे कोई फर्क नहीं पड़ता अगर हम उन्हें खुद को कुछ इष्टतम तरीके से ठीक कर सकते हैं, लेकिन अक्सर हम नहीं कर सकते।

अद्यतन: यहां तक ​​कि हाथ से जाने के लिए, मैंने .NET सरणियों का उल्लेख किया जो एक इंटरफ़ेस का समर्थन नहीं करता है जो स्थिति द्वारा यादृच्छिक अभिगम का समर्थन करता है (मेरी टिप्पणी भी देखें)। लेकिन .NET 4.5 में सटीक इंटरफ़ेस को परिभाषित किया गया है और सरणियों और List<T>वर्ग द्वारा समर्थित है :

IReadOnlyList<int> a = new[] {1, 2, 3, 4};
IReadOnlyList<int> b = new List<int> { 1, 2, 3, 4 };

सभी अभी भी काफी सही नहीं है क्योंकि परिवर्तनशील सूची इंटरफ़ेस IList<T>विरासत में नहीं है IReadOnlyList<T>:

IList<int> c = new List<int> { 1, 2, 3, 4 };
IReadOnlyList<int> d = c; // error

हो सकता है कि इस तरह के बदलाव के साथ एक संभव पिछड़ा संगतता हो।

यदि जावा के नए संस्करणों में इसी तरह की चीजों पर कोई प्रगति है, तो मुझे टिप्पणियों में जानने में दिलचस्पी होगी! :)


8
.NET सरणियाँ IList इंटरफ़ेस को लागू करती हैं
टॉम गिलेन

2
@Aphid - मैंने कहा केवल पढ़ने के लिए रैंडम एक्सेस। IList<T>संशोधन के लिए संचालन को उजागर करता है। यह बहुत अच्छा होगा यदि आपको इंटरफ़ेस IList<T>जैसा कुछ विरासत में मिला है IReadonlyList<T>, जो कि सिर्फ Countऔर सिर्फ T this[int]विरासत में मिला होगा और IEnumerable<T>(जो पहले से ही सहज ज्ञान का समर्थन करता है)। एक और बढ़िया बात एक रिवर्स-ऑर्डर एन्यूमरेटर प्राप्त करने के लिए एक इंटरफ़ेस होगा, जो Reverseविस्तार विधि के लिए क्वेरी कर सकता है (जैसे कि स्वयं को अनुकूलित Countकरने के लिए एक्सटेंशन विधि क्वेरी ICollection।)
डैनियल ईयरविकेर

हां, यह बहुत बेहतर होगा अगर चीजें इस तरह से डिजाइन की गई हों। IList इंटरफ़ेस IsReadOnly और IsFixedSize गुणों को परिभाषित करता है, जिन्हें सरणी द्वारा उचित रूप से लागू किया जाता है। यह हमेशा मुझे ऐसा करने के एक बहुत बुरे तरीके के रूप में मारा गया है, क्योंकि यह कोई संकलन समय की जाँच नहीं करता है कि आपको जो सूची दी गई है वह वास्तव में आसानी से है, और मैं बहुत कम ही कोड देखता हूं जो इन गुणों की जांच करता है।
टॉम गिलेन

1
.NET में सरणी को लागू IListऔर ICollection.NET 1.1 के बाद से, और IList<T>और ICollection<T>.NET 2.0 के बाद से। यह अभी तक एक और मामला है जहां जावा प्रतियोगिता से बहुत पीछे है।
अमीर अबीरी

@TomGillen: इसके साथ मेरी सबसे बड़ी समस्या IListयह है कि यह अधिक उपयोगी विशेषताएं प्रदान नहीं करता है। मैं कहूंगा कि समुचित सेट में IsUpdateable, IsResizable, IsReadOnly, IsFixedSize और Ex मौजूदाElementsAreImmutable शामिल होने चाहिए। कोड का संदर्भ, टाइपकास्टिंग के बिना, एक सूची को संशोधित कर सकता है या नहीं, इस सवाल से अलग है कि क्या कोड, जो उस सूची का संदर्भ रखता है जिसे संशोधित करने की आवश्यकता नहीं है, उस संदर्भ को बाहरी कोड के साथ सीधे साझा कर सकता है, या क्या यह सुरक्षित रूप से मान सकता है कि सूची का कोई पहलू कभी नहीं बदलेगा।
सुपरकैट

14

दुर्भाग्य से, सरणियाँ 'नहीं' नहीं हैं class। वे Iterableइंटरफ़ेस को लागू नहीं करते हैं ।

जबकि सरणियाँ अब ऑब्जेक्ट हैं जो क्लोन करने योग्य और सीरियल को लागू करते हैं, मेरा मानना ​​है कि एक सरणी सामान्य अर्थ में एक वस्तु नहीं है , और इंटरफ़ेस को लागू नहीं करता है।

कारण है कि आप उन्हें प्रत्येक लूप में उपयोग कर सकते हैं क्योंकि सूर्य सरणियों के लिए कुछ सिन्थेटिक चीनी में जोड़ा गया है (यह एक विशेष मामला है)।

चूँकि सरणियाँ जावा 1 के साथ 'लगभग ऑब्जेक्ट्स' के रूप में शुरू हुई थीं, इसलिए यह जावा में उन्हें वास्तविक ऑब्जेक्ट बनाने के लिए एक बदलाव के लिए बहुत अधिक कठोर होगा ।


14
फिर भी, प्रत्येक लूप के लिए चीनी है, इसलिए Iterable के लिए चीनी क्यों नहीं हो सकती है?
माइकल मायर्स

8
@ खरीदार: प्रत्येक के लिए उपयोग की जाने वाली चीनी संकलित चीनी है। यह वीएम शुगर की तुलना में बहुत आसान है । किसने कहा, इस क्षेत्र में .NET सरणियाँ काफी बेहतर हैं ...
जॉन स्कीट

12
अंतराल इंटरफेस को लागू कर सकते हैं । वे लागू करते हैं Cloneableऔर Serializableइंटरफेस करते हैं।
notnoop

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

5
एक सरणी एक वस्तु है। यह उपयोगी का समर्थन करता है : पी तरीके जैसे प्रतीक्षा (), प्रतीक्षा (एन), प्रतीक्षा (एन, एम), सूचित (), सूचित करें (), अंतिम रूप (), स्ट्रींग का एक व्यर्थ कार्यान्वयन () एकमात्र उपयोगी तरीका है getClass () ।
पीटर लॉरी

1

कंपाइलर वास्तव में for eachएक सरणी पर forएक काउंटर चर के साथ एक साधारण लूप में अनुवाद करता है ।

निम्नलिखित संकलन

public void doArrayForEach() {
    int[] ints = new int[5];

    for(int i : ints) {
        System.out.println(i);
    }
}

और फिर .class फ़ाइल की उपज घटा कर

public void doArrayForEach() {
    int[] ints = new int[5];
    int[] var2 = ints;
    int var3 = ints.length;

    for(int var4 = 0; var4 < var3; ++var4) {
        int i = var2[var4];
        System.out.println(i);
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.