[java] जावा में सूची बनाम प्रकार ArrayList टाइप करें



Answers

मैं सोच रहा हूं कि कोई भी (2) का उपयोग करता है?

हाँ। लेकिन शायद ही कभी एक अच्छे कारण के लिए।

और कभी-कभी लोग जलाते हैं क्योंकि उन्होंने ArrayList उपयोग किया था जब उन्हें इस्तेमाल किया जाना चाहिए List :

  • Collections.singletonList(...) Arrays.asList(...) या Arrays.asList(...) जैसे उपयोगिता विधियों को एक ArrayList वापस नहीं करते हैं।

  • List एपीआई के तरीके एक ही प्रकार की सूची वापस करने की गारंटी नहीं देते हैं।

उदाहरण के लिए, https://stackoverflow.com/a/1481123/139985 में पोस्टर को "स्लाइसिंग" के साथ समस्याएं थीं क्योंकि ArrayList.sublist(...) एक ArrayList वापस नहीं करता है ... और उसने अपना कोड डिज़ाइन किया था ArrayList उपयोग अपनी सभी सूची चर के प्रकार के रूप में करें। उन्होंने एक नए ArrayList में sublist की प्रतिलिपि बनाकर समस्या को हल करने "समाप्त" किया।

यह तर्क कि आपको यह जानने की आवश्यकता है कि List कैसे व्यवहार करती है उसे बड़े पैमाने पर RandomAccess मार्कर इंटरफ़ेस का उपयोग करके संबोधित किया जाता है। हां, यह थोड़ा गुंजाइश है, लेकिन विकल्प खराब है।

साथ ही, वास्तव में स्थिति (1) से अधिक (2) (यानी जहां (2) पर्याप्त नहीं होगा .. 'इंटरफेस को कोडिंग' और सर्वोत्तम प्रथाओं आदि के आधार पर वास्तव में कितनी बार आवश्यकता होती है)

प्रश्न का "कितनी बार" हिस्सा निष्पक्ष रूप से असंभव है।

(और क्या मैं एक उदाहरण प्राप्त कर सकता हूं)

कभी-कभी, एप्लिकेशन की आवश्यकता हो सकती है कि आप ArrayList API में विधियों का उपयोग करें जो List API में नहीं हैं। उदाहरण के लिए, ensureCapacity(int) , trimToSize() या removeRange(int, int) । (और आखिरी वाला केवल तभी उत्पन्न होगा जब आपने ऐरेलिस्ट का उप-प्रकार बनाया है जो public होने की विधि घोषित करता है।)

इंटरफ़ेस, आईएमओ की बजाय कक्षा में कोडिंग के लिए यही एकमात्र ध्वनि कारण है।

(यह सैद्धांतिक रूप से संभव है कि आपको प्रदर्शन में थोड़ा सुधार मिलेगा ... कुछ परिस्थितियों में ... कुछ प्लेटफार्मों पर ... लेकिन जब तक आपको वास्तव में उस अंतिम 0.05% की आवश्यकता नहीं है, यह करने योग्य नहीं है। यह एक नहीं है ध्वनि कारण, आईएमओ।)

यदि आप नहीं जानते कि यादृच्छिक पहुंच कुशल है या नहीं, तो आप कुशल कोड नहीं लिख सकते हैं।

यह एक वैध बिंदु है। हालांकि, जावा उस से निपटने के बेहतर तरीके प्रदान करता है; जैसे

public <T extends List & RandomAccess> void test(T list) {
    // do stuff
}

यदि आप उस सूची के साथ कॉल करते हैं जो RandomAccess लागू नहीं करता है तो आपको संकलन त्रुटि मिल जाएगी।

आप गतिशील रूप से परीक्षण भी कर सकते हैं ... instanceof का उपयोग कर ... यदि स्थैतिक टाइपिंग बहुत अजीब है। और आप अलग-अलग एल्गोरिदम (गतिशील रूप से) का उपयोग करने के लिए अपना कोड भी लिख सकते हैं, इस पर निर्भर करता है कि कोई सूची यादृच्छिक पहुंच समर्थित है या नहीं।

ध्यान दें कि ArrayList एकमात्र सूची वर्ग नहीं है जो RandomAccess लागू करता है। अन्य में CopyOnWriteList , Stack और Vector

मैंने देखा है कि लोग Serializable बारे में एक ही तर्क करते हैं (क्योंकि List इसे लागू नहीं करती है) ... लेकिन उपरोक्त दृष्टिकोण भी इस समस्या को हल करता है। (इस हद तक कि यह रनटाइम प्रकारों का उपयोग कर हल करने योग्य है । यदि कोई तत्व धारावाहिक नहीं है तो एक ArrayList serialization विफल हो जाएगा।)

Question
(1) List<?> myList = new ArrayList<?>();

(2) ArrayList<?> myList = new ArrayList<?>();

मैं समझता हूं कि (1) के साथ, सूची इंटरफ़ेस के कार्यान्वयन को बदला जा सकता है। ऐसा लगता है कि (1) आम तौर पर आवश्यकता के बावजूद किसी एप्लिकेशन में उपयोग किया जाता है (मैं हमेशा इसका उपयोग करता हूं)।

मैं सोच रहा हूं कि कोई भी (2) का उपयोग करता है?

साथ ही, कितनी बार (और मैं एक उदाहरण प्राप्त कर सकता हूं) क्या स्थिति वास्तव में (1) से अधिक (2) (यानी जहां (2) पर्याप्त नहीं होगी .. इंटरफेस और सर्वोत्तम प्रथाओं आदि के लिए कोडिंग के अलावा )




निम्नलिखित दो में से:

(1) List<?> myList = new ArrayList<?>();
(2) ArrayList<?> myList = new ArrayList<?>();

सबसे पहले आम तौर पर पसंद किया जाता है। चूंकि आप केवल List इंटरफ़ेस से विधियों का उपयोग करेंगे, यह आपको भविष्य में LinkedList जैसे List कुछ अन्य कार्यान्वयन का उपयोग करने की स्वतंत्रता प्रदान करता है। तो यह आपको विशिष्ट कार्यान्वयन से decouples। अब उल्लेख करने के लायक दो अंक हैं:

  1. हमें हमेशा इंटरफेस के लिए प्रोग्राम करना चाहिए। here और अधिक
  2. आप ArrayList पर ArrayList का उपयोग करके लगभग हमेशा समाप्त हो जाएंगे। here और अधिक

मैं सोच रहा हूं कि कोई भी उपयोग करता है (2)

हां कभी-कभी (शायद ही कभी पढ़ा जाता है)। जब हमें उन तरीकों की आवश्यकता होती है जो ArrayList के कार्यान्वयन का हिस्सा हैं लेकिन इंटरफ़ेस List का हिस्सा नहीं हैं। उदाहरण के लिए ensureCapacity

साथ ही, कितनी बार (और मैं एक उदाहरण प्राप्त कर सकता हूं) क्या वास्तव में स्थिति (1) से अधिक (2) का उपयोग करने की आवश्यकता होती है

लगभग हमेशा आप विकल्प पसंद करते हैं (1)। यह ओओपी में शास्त्रीय डिज़ाइन पैटर्न है जहां आप हमेशा अपने कोड को विशिष्ट कार्यान्वयन और प्रोग्राम से इंटरफ़ेस में डीकुल करने का प्रयास करते हैं।




मैं कहूंगा कि 1 को प्राथमिकता दी जाती है

  • आप ArrayList में वैकल्पिक व्यवहार * के कार्यान्वयन के आधार पर हैं, उस मामले में स्पष्ट रूप से ArrayList का उपयोग करना अधिक स्पष्ट है
  • आप एक विधि कॉल में ArrayList का उपयोग करेंगे जिसके लिए संभवतः वैकल्पिक व्यवहार या प्रदर्शन विशेषताओं के लिए ArrayList की आवश्यकता होती है

मेरा अनुमान है कि 99% मामलों में आप सूची के साथ प्राप्त कर सकते हैं, जिसे प्राथमिकता दी जाती है।

  • उदाहरण के लिए add(null) , या add(null)



दरअसल ऐसे मौके होते हैं जहां (2) न केवल पसंदीदा बल्कि अनिवार्य है और मैं बहुत हैरान हूं, कि कोई भी इसका उल्लेख नहीं करता है।

क्रमबद्धता!

यदि आपके पास एक धारावाहिक वर्ग है और आप इसे एक सूची में रखना चाहते हैं, तो आपको फ़ील्ड को कंक्रीट और धारावाहिक प्रकार के रूप में घोषित करना होगा जैसे कि ArrayList क्योंकि List इंटरफ़ेस java.io.Serializable विस्तार नहीं करता है। Serializable

जाहिर है ज्यादातर लोगों को क्रमबद्ध करने की आवश्यकता नहीं है और इसके बारे में भूल जाओ।

एक उदाहरण:

public class ExampleData implements java.io.Serializable {

// The following also guarantees that strings is always an ArrayList.
private final ArrayList<String> strings = new ArrayList<>();



इसे सेट सेट के चर में HashSet या TreeSet संदर्भ को स्टोर करने के लिए अच्छी शैली माना जाता है

Set<String> names = new HashSet<String>();

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

साथ ही, सेट पर चलने वाली विधियों को टाइप सेट के पैरामीटर निर्दिष्ट करना चाहिए:

public static void print(Set<String> s)

फिर विधि को सभी सेट कार्यान्वयन के लिए उपयोग किया जा सकता है

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

यदि आप नहीं जानते कि यादृच्छिक पहुंच कुशल है या नहीं, तो आप कुशल कोड नहीं लिख सकते हैं।

यह मानक पुस्तकालय में स्पष्ट रूप से एक गंभीर डिजाइन त्रुटि है, और मैं उस कारण से सूची इंटरफ़ेस का उपयोग करने की अनुशंसा नहीं कर सकता।

यह देखने के लिए कि त्रुटि कितनी शर्मनाक है, संग्रह वर्ग की binarySearch विधि के लिए स्रोत कोड पर नज़र डालें। वह विधि एक सूची पैरामीटर लेती है, लेकिन बाइनरी खोज किसी लिंक की गई सूची के लिए कोई समझ नहीं लेती है। कोड तब यह पता लगाने की कोशिश करता है कि सूची एक लिंक्ड सूची है या नहीं, और उसके बाद एक रैखिक खोज में स्विच करता है!

Set इंटरफ़ेस और Map इंटरफ़ेस अच्छी तरह डिज़ाइन किए गए हैं, और आपको उनका उपयोग करना चाहिए।




सूची एक इंटरफ़ेस है। इसमें विधियां नहीं हैं। जब आप एक सूची संदर्भ पर विधि कॉल करते हैं। यह वास्तव में दोनों मामलों में ArrayList की विधि को बुलाता है।

और भविष्य के लिए आप List obj = new ArrayList<> List obj = new LinkList<> या अन्य प्रकार को सूचीबद्ध कर सकते हैं जो सूची इंटरफ़ेस लागू करता है।









Links