हमारे पास एक विशेषता के रूप में एक सरणी की लंबाई क्यों है array.length, और स्ट्रिंग के लिए हमारे पास एक विधि है,str.length() ,?
क्या कुछ कारण है?
हमारे पास एक विशेषता के रूप में एक सरणी की लंबाई क्यों है array.length, और स्ट्रिंग के लिए हमारे पास एक विधि है,str.length() ,?
क्या कुछ कारण है?
जवाबों:
मुझे पहले समान उद्देश्य के लिए तीन अलग-अलग तरीकों पर प्रकाश डालते हैं।
length- सरणियों ( int[], double[],String[] ) - सरणियों की लंबाई पता करने के लिए
length()- स्ट्रिंग संबंधित वस्तु ( Stringऔर StringBuilder, आदि) - स्ट्रिंग की लंबाई जानने के लिए
size()- संग्रह का आकार जानने के लिए संग्रह वस्तु ( ArrayList, Setआदि)
अब के बारे में भूल length()बस पर विचार lengthऔर size()।
lengthएक विधि नहीं है, इसलिए यह पूरी तरह से समझ में आता है कि यह वस्तुओं पर काम नहीं करेगा। यह केवल सरणियों पर काम करता है।
size()इसका नाम इसका बेहतर वर्णन करता है और जैसा कि यह एक विधि है, इसका उपयोग उन वस्तुओं के मामले में किया जाएगा जो संग्रह (संग्रह चौखटे) के साथ काम करते हैं जैसा कि मैंने वहां कहा था।
अब आते हैं length():
स्ट्रिंग एक आदिम सरणी नहीं है (इसलिए हम उपयोग नहीं कर सकते हैं .length) और एक संग्रह भी नहीं है (इसलिए हम उपयोग नहीं कर सकते हैं .size()) इसलिए हमें एक अलग की भी आवश्यकता है जोlength() (अंतर रखें और उद्देश्य की सेवा करें)।
उत्तर के रूप में क्यों?
मुझे यह उपयोगी, याद रखने में आसान और उपयोग और अनुकूल लगता है।
थोड़ा सरलीकृत आप इसे एक विशेष मामला होने के रूप में सरणियों के रूप में सोच सकते हैं और सामान्य कक्षाएं (आदिम की तरह थोड़ा नहीं, लेकिन नहीं)। स्ट्रिंग और सभी संग्रह कक्षाएं हैं, इसलिए आकार, लंबाई या इसी तरह की चीजें प्राप्त करने के तरीके।
मुझे लगता है कि डिजाइन के प्रदर्शन के समय कारण था। अगर आज उन्होंने इसे बनाया तो वे शायद इसके बजाय सरणी-समर्थित संग्रह कक्षाओं जैसे कुछ के साथ आए थे।
अगर किसी को दिलचस्पी है, तो यहां उत्पन्न कोड में दो के बीच अंतर को स्पष्ट करने के लिए कोड का एक छोटा सा स्निपेट है, पहला स्रोत:
public class LengthTest {
public static void main(String[] args) {
int[] array = {12,1,4};
String string = "Hoo";
System.out.println(array.length);
System.out.println(string.length());
}
}
एक तरह से बाइट कोड का इतना महत्वपूर्ण हिस्सा नहीं काटना javap -c, दो अंतिम पंक्तियों के लिए निम्नलिखित में वर्ग परिणामों पर चल रहा है :
20: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
23: aload_1
24: arraylength
25: invokevirtual #4; //Method java/io/PrintStream.println:(I)V
28: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
31: aload_2
32: invokevirtual #5; //Method java/lang/String.length:()I
35: invokevirtual #4; //Method java/io/PrintStream.println:(I)V
पहले मामले में (20-25) कोड सिर्फ JVM को सरणी के आकार के लिए पूछता है (JNI में यह GetArrayLength () के लिए एक कॉल होता है) जबकि स्ट्रिंग मामले (28-35) में इसे करने की आवश्यकता होती है लंबाई प्राप्त करने के लिए विधि कॉल।
1990 के दशक के मध्य में, अच्छे JIT और सामान के बिना, इसने प्रदर्शन को पूरी तरह से मार दिया होगा केवल java.util.Vector (या कुछ इसी तरह) और न ही एक भाषा निर्माण जो वास्तव में एक वर्ग की तरह व्यवहार नहीं करता था, लेकिन तेज था। वे निश्चित रूप से संपत्ति को एक विधि कॉल के रूप में मुखौटा बना सकते थे और इसे संकलक में संभाला करते थे, लेकिन मुझे लगता है कि यह उस चीज़ पर एक विधि होने के लिए और भी भ्रामक होगा जो वास्तविक वर्ग नहीं है।
Vectorजब जावा भाषा में कोई सरणी समर्थन नहीं था तो आप कैसे लागू करेंगे ?
विचार करें:
int[] myArray = new int[10];
String myString = "hello world!";
List<int> myList = new ArrayList<int>();
myArray.length // Gives the length of the array
myString.length() // Gives the length of the string
myList.size() // Gives the length of the list
यह बहुत संभावना है कि स्ट्रिंग्स और सरणियों को अलग-अलग समय पर डिज़ाइन किया गया था और इसलिए विभिन्न सम्मेलनों का उपयोग करके समाप्त हो गया। एक औचित्य यह है कि चूंकि स्ट्रिंग्स आंतरिक रूप से सरणियों का उपयोग करते हैं, इसलिए एक length()ही जानकारी के दोहराव से बचने के लिए एक विधि का उपयोग किया गया था। एक और यह है कि एक विधि का उपयोग करने length()से स्ट्रिंग्स की अपरिहार्यता पर जोर देने में मदद मिलती है, भले ही एक सरणी का आकार भी अपरिवर्तनीय हो।
अंतत: यह सिर्फ एक असंगति है जो विकसित हुई है जो निश्चित रूप से तय होगी यदि भाषा को कभी भी जमीन से फिर से जोड़ा जाए। जहां तक मुझे पता है कि कोई अन्य भाषा (C #, पायथन, स्काला, आदि) एक ही काम नहीं करती है, इसलिए यह संभवतः एक मामूली दोष है जो भाषा के हिस्से के रूप में समाप्त हो गया है।
यदि आप किसी भी तरह से गलत का उपयोग करते हैं तो आपको एक त्रुटि मिलेगी।
जावा में, एक ऐरे संरचना से अलग अपनी लंबाई संग्रहीत करता है जो वास्तव में डेटा रखती है। जब आप कोई ऐरे बनाते हैं, तो आप उसकी लंबाई निर्दिष्ट करते हैं, और वह एरे का एक परिभाषित करने वाला गुण बन जाता है। कोई फर्क नहीं पड़ता कि आप लंबाई N के एक ऐरे के लिए क्या करते हैं (मान बदलते हैं, अशक्त बातें, आदि), यह हमेशा लंबाई एन का एक ऐरे होगा।
एक स्ट्रिंग की लंबाई आकस्मिक है; यह स्ट्रिंग का एक गुण नहीं है, लेकिन एक उपोत्पाद है। हालांकि जावा स्ट्रिंग्स वास्तव में अपरिवर्तनीय हैं, अगर उनकी सामग्री को बदलना संभव था, तो आप उनकी लंबाई बदल सकते हैं। अंतिम चरित्र को बंद करना (यदि यह संभव था) लंबाई कम होगी।
मैं समझता हूं कि यह एक अच्छा अंतर है, और मैं इसके लिए वोट कर सकता हूं, लेकिन यह सच है। यदि मैं लंबाई 4 का एक ऐरे करता हूं, तो चार की लंबाई एरे की एक परिभाषित विशेषता है, और जो भी भीतर आयोजित किया गया है, उसकी परवाह किए बिना सच है। अगर मैं एक स्ट्रिंग बनाता हूं जिसमें "कुत्ते" शामिल हैं, तो वह स्ट्रिंग की लंबाई 4 है क्योंकि इसमें चार वर्ण होते हैं।
मैं इसे एक विशेषता के साथ एक और एक विधि के साथ करने के औचित्य के रूप में देखता हूं। सच में, यह सिर्फ एक अनजाने असंगतता हो सकती है, लेकिन यह हमेशा मेरे लिए समझ में आता है, और यह हमेशा है कि मैंने इसके बारे में कैसे सोचा है।
मुझे सिखाया गया था कि सरणियों के लिए, लंबाई को निम्नलिखित भय के कारण एक विधि के माध्यम से पुनर्प्राप्त नहीं किया जाता है: प्रोग्रामर सिर्फ एक लूप दर्ज करने से पहले एक स्थानीय चर को लंबाई असाइन करेंगे (लगता है कि लूप के लिए जहां सशर्त सरणी की लंबाई का उपयोग करता है।) प्रोग्रामर। माना जाता है कि यह फ़ंक्शन कॉल पर ट्रिम करने के लिए है (और इस तरह प्रदर्शन में सुधार होगा।) समस्या यह है कि लूप के दौरान लंबाई बदल सकती है, और चर नहीं होगा।
जब भी कोई सरणी बनाई जाती है, तो उसका आकार निर्दिष्ट किया जाता है। तो लंबाई एक निर्माण विशेषता के रूप में माना जा सकता है। स्ट्रिंग के लिए, यह अनिवार्य रूप से एक चार सरणी है। लंबाई वर्ण सरणी की एक संपत्ति है। एक क्षेत्र के रूप में लंबाई डालने की आवश्यकता नहीं है, क्योंकि इस क्षेत्र में सब कुछ की आवश्यकता नहीं है। http://www.programcreek.com/2013/11/start-from-length-length-in-java/
मैं सिर्फ महान करने के लिए कुछ टिप्पणी जोड़ना चाहते हैं जवाब से फ्रेड्रिक ।
धारा में 4.3.1 जावा भाषा विशिष्टता राज्यों
एक वस्तु एक श्रेणी उदाहरण या एक सरणी है ।
तो जावा में सरणी वास्तव में एक बहुत ही विशेष भूमिका है। मुझे आश्चर्य है कि क्यों।
एक तर्क दे सकता है कि एक बेहतर प्रदर्शन के लिए वर्तमान कार्यान्वयन सरणी / महत्वपूर्ण थी। लेकिन यह एक आंतरिक संरचना है, जिसे उजागर नहीं किया जाना चाहिए।
वे निश्चित रूप से एक संपत्ति कॉल के रूप में संपत्ति को मुखौटा कर सकते हैं और इसे संकलक में संभाला है, लेकिन मुझे लगता है कि यह उस चीज़ पर एक विधि होने के लिए और भी भ्रामक होगा जो वास्तविक वर्ग नहीं है।
मैं फ्रेड्रिक से सहमत हूं, कि स्मार्ट कंपाइलर ऑप्टिमाइज़ेशन बेहतर विकल्प होता। इससे समस्या का समाधान भी होगा, कि यदि आप सरणियों के लिए एक संपत्ति का उपयोग करते हैं, तो भी आपने तार और अन्य (अपरिवर्तनीय) संग्रह प्रकारों के लिए समस्या का समाधान नहीं किया है, क्योंकि, उदाहरण के लिए, stringएक charसरणी पर आधारित है जैसा कि आप वर्ग परिभाषा पर देख सकते हैं। का String:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[]; // ...
और मैं इससे सहमत नहीं हूं कि यह और भी भ्रामक होगा, क्योंकि सरणी सभी तरीकों सेjava.lang.Object विरासत में मिली है ।
एक इंजीनियर के रूप में मुझे वास्तव में जवाब पसंद नहीं है "क्योंकि यह हमेशा इस तरह से रहा है।" और काश एक बेहतर जवाब होता। लेकिन इस मामले में ऐसा लगता है।
tl; डॉ
मेरी राय में, यह जावा का डिज़ाइन दोष है और इसे इस तरह से लागू नहीं किया जाना चाहिए।