जावा में चर बनाम वीरता?


421

एंड्रॉइड में प्रोग्रामिंग, अधिकांश पाठ मूल्यों में अपेक्षित हैं CharSequence

ऐसा क्यों है? लाभ क्या है, और का उपयोग करने का मुख्य प्रभाव डालता है क्या कर रहे हैं CharSequenceसे अधिक String?

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


जवाबों:


343

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


94
सिवाय जब एंड्रॉइड मुझे कॉलबैक में एक चार्जसेंस पास करता है और मुझे एक स्ट्रिंग - कॉल charSeq.toString () की आवश्यकता होती है।
मार्टिन कोनिसक

100
लेकिन इस कैविएट को CharSequenceजेवार्डोक से ध्यान में रखें : यह इंटरफ़ेस सामान्य तरीके equalsऔर hashCodeविधियों के अनुबंध को परिष्कृत नहीं करता है । CharSequenceइसलिए लागू होने वाली दो वस्तुओं की तुलना करने का नतीजा , सामान्य तौर पर, अपरिभाषित है । प्रत्येक वस्तु को एक अलग वर्ग द्वारा लागू किया जा सकता है, और इसमें कोई गारंटी नहीं है कि प्रत्येक वर्ग दूसरे लोगों के साथ समानता के लिए अपने उदाहरणों का परीक्षण करने में सक्षम होगा। इसलिए CharSequenceएक सेट में तत्वों के रूप में या नक्शे में कुंजियों के रूप में मनमाना उदाहरणों का उपयोग करना अनुचित है ।
ट्रेवर रॉबिन्सन

3
@ स्पेसर: मुझे लगता है कि यह एक व्यावहारिक सीमा है। CharSequenceJDK 1.4 में एक रेट्रोफिट था जो चरित्र अनुक्रम वाली वस्तुओं के लिए एक सीमित-उद्देश्य वाले सामान्य इंटरफ़ेस को पेश करता था। उन वस्तुओं में से कुछ में अन्य राज्य होते हैं, इसलिए इसे Object.equals"समान वर्ण अनुक्रम" के रूप में परिभाषित करने के लिए समझ में नहीं आ सकता है । CharBufferउदाहरण के लिए, NIO , केवल इसके positionऔर इसके बीच के पात्रों को उजागर करता limitहै CharSequence, संभावित रूप से कई अन्य पात्रों को धारण करने के बावजूद।
ट्रेवर रॉबिन्सन

6
@TrevorRobinson, इसलिए डिज़ाइन बग पहले स्थान पर है equals/ है ....hashCodeObject
Pacerier

4
@ स्पेसर: आईएमएचओ Objectया तो एक डिज़ाइन बग नहीं है या CharSequence, कार्यान्वयन के बीच समानता पवित्रता प्रदान करने के लिए किसी इंटरफ़ेस की आवश्यकता नहीं है। इंटरफ़ेस के Collectionबीच समानता प्रदान करने के लिए किसी भी दो एस की आवश्यकता नहीं होती है Collection, लेकिन यदि वे चुनते हैं तो वे कर सकते हैं। IMHO CharSequenceइनपुट तक सीमित होना चाहिए और रिटर्न प्रकारों के लिए कम उपयोग किया जाना चाहिए।
ब्रेट रायन

58

CharSequence= इंटरफ़ेस
String= ठोस कार्यान्वयन

तुमने कहा था:

एक से दूसरे में परिवर्तित करना

से कोई रूपांतरित नहीं होता है String

  • हर Stringवस्तु है एक CharSequence
  • हर CharSequenceएक का उत्पादन कर सकते हैं String। पुकारते हैं CharSequence::toString। यदि CharSequenceऐसा होता है String, तो विधि अपनी वस्तु का संदर्भ देती है।

दूसरे शब्दों में, हर Stringएक है CharSequence, लेकिन हर CharSequenceएक नहीं है String

एक अंतरफलक के लिए प्रोग्रामिंग

एंड्रॉइड में प्रोग्रामिंग करना, अधिकांश पाठ मूल्यों में चारसेंसेंस में अपेक्षित हैं।

ऐसा क्यों है? लाभ क्या है, और स्ट्रिंग पर CharSequence का उपयोग करने के मुख्य प्रभाव क्या हैं?

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

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

उदाहरण के लिए, जावा कलेक्शंस फ्रेमवर्क को देखें । अपने एपीआई देता है या वस्तुओं का एक आदेश दिया संग्रह लेता है, के रूप में उपयोग करते हुए अपने तरीकों की घोषणा Listकरने के बजाय ArrayList, LinkedListया किसी भी अन्य 3-पक्ष कार्यान्वयन List

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

उपयोग करते समय मुख्य अंतर क्या हैं, और क्या मुद्दे अपेक्षित हैं,

  • एक के साथ Stringक्या आप जानते हैं कि आप पाठ के एक टुकड़े है, पूरी तरह से स्मृति में, और अपरिवर्तनीय है।
  • ए के साथ CharSequence, आपको नहीं पता कि कंक्रीट कार्यान्वयन की विशेष विशेषताएं क्या हो सकती हैं।

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

और एक से दूसरे में परिवर्तित?

आप आम तौर पर आगे और पीछे परिवर्तित नहीं होंगे। ए String हैCharSequence। अपने विधि घोषणा करता है कि यह एक लेता है CharSequence, बुला प्रोग्रामर एक पास कर सकते हैं Stringवस्तु, या एक के रूप में कुछ और इस तरह के पास कर सकते हैं StringBufferया StringBuilder। आपके विधि का कोड बस जो भी पारित किया जाता है, किसी भी CharSequenceतरीके का उपयोग करेगा।

यदि आप अपने कोड को प्राप्त करते हैं, तो आप निकटतम रूप से परिवर्तित हो जाएंगे CharSequenceऔर आपको पता होगा कि आपको इसकी आवश्यकता है String। शायद आपका इंटरफ़ेस के लिए लिखे जाने के Stringबजाय कक्षा के लिए लिखे गए पुराने कोड के साथ हस्तक्षेप कर रहा CharSequenceहै। या शायद आपका कोड पाठ के साथ गहन रूप से काम करेगा, जैसे बार-बार लूपिंग या अन्यथा विश्लेषण करना। उस स्थिति में, आप किसी भी संभावित प्रदर्शन को केवल एक बार हिट करना चाहते हैं, इसलिए आप toStringसामने बुलाते हैं । फिर अपने काम के साथ आगे बढ़ें जो आप जानते हैं कि पाठ का एक टुकड़ा पूरी तरह से स्मृति में है।

मुड़ इतिहास

स्वीकृत उत्तर पर की गई टिप्पणियों पर ध्यान देंCharSequenceइंटरफ़ेस मौजूदा वर्ग संरचना पर retrofitted किया गया था, तो वहाँ कुछ महत्वपूर्ण बारीकियों (हैं equals()और hashCode())। जावा के विभिन्न संस्करणों (1, 2, 4 और 5) को देखें, जो पिछले कुछ वर्षों में कक्षाओं / इंटरफेसों पर काफी चर्चित रहे हैं। आदर्श रूप CharSequenceमें शुरुआत से ही होता है, लेकिन ऐसा ही जीवन है।

नीचे मेरा वर्ग आरेख आपको जावा 7/8 में स्ट्रिंग प्रकारों की बड़ी तस्वीर देखने में मदद कर सकता है। मुझे यकीन नहीं है कि ये सभी एंड्रॉइड में मौजूद हैं, लेकिन समग्र संदर्भ अभी भी आपके लिए उपयोगी साबित हो सकता है।

विभिन्न स्ट्रिंग-संबंधित कक्षाओं और इंटरफेस का आरेख


2
क्या आपने यह चित्र स्वयं बनाया है? सोच रहा था कि क्या अलग-अलग डेटा संरचनाओं के लिए इन आरेखों की एक सूची है।
user171943

4
@ user171943 निरूपित मेरे द्वारा, हाथ से तैयार का उपयोग कर OmniGraffle OmniGroup से एप्लिकेशन को।
तुलसी बॉर्क

37

मेरा मानना ​​है कि CharSequence का उपयोग करना सबसे अच्छा है। इसका कारण यह है कि स्ट्रिंग इम्प्रूवमेंट CharSequence है, इसलिए आप एक String को CharSequence में पास कर सकते हैं, यदि आप CharSequence को String में पास नहीं कर सकते, क्योंकि CharSequence String को लागू नहीं करता है। ALSO, Android में EditText.getText()विधि एक संपादन योग्य देता है, जो चारसेंपेंस को भी लागू करता है और इसे आसानी से एक में पारित किया जा सकता है, जबकि आसानी से स्ट्रिंग में नहीं। CharSequence सभी संभालती है!


7
आप कर सकते हैंcharSequence.toString()
जॉर्ज फ्यूएंटेस गोंजालेज

1
@ जोर्ज: सिवाय इसके कि अगर उत्परिवर्तनीय (या किसी भी कारण से अपरिवर्तनीय स्ट्रिंग में बनाने के लिए वर्णों की एक प्रति की आवश्यकता होती है) तो अपेक्षाकृत अक्षम होगा।
लॉरेंस डॉल

बहुत अच्छी व्याख्या ..!
मजूरगेटर्टन

23

सामान्य तौर पर एक इंटरफ़ेस का उपयोग करने से आप न्यूनतम संपार्श्विक क्षति के साथ कार्यान्वयन को भिन्न कर सकते हैं। यद्यपि java.lang.String सुपर लोकप्रिय हैं लेकिन यह संभव है कि कुछ संदर्भों में कोई अन्य कार्यान्वयन का उपयोग करना चाहे। स्ट्रिंग्स के बजाय CharSequences के चारों ओर एपीआई का निर्माण करके कोड एक को ऐसा करने का अवसर देता है।


8

यह लगभग निश्चित रूप से प्रदर्शन कारण है। उदाहरण के लिए, एक पार्लर की कल्पना करें जो 500k बाइटबफ़र से होकर गुजरता है।

स्ट्रिंग सामग्री वापस करने के लिए 3 दृष्टिकोण हैं:

  1. एक समय में एक चरित्र, एक समय में एक स्ट्रिंग [] का निर्माण करें। यह ध्यान देने योग्य समय लगेगा। कैश्ड संदर्भों की तुलना करने के लिए हम। = का उपयोग कर सकते हैं।

  2. पार्स समय में ऑफ़सेट के साथ एक इंट [] बनाएँ, फिर जब () होता है तब गतिशील रूप से स्ट्रिंग का निर्माण करते हैं। प्रत्येक स्ट्रिंग एक नई वस्तु होगी, इसलिए कोई कैशिंग लौटाए गए मान और == का उपयोग नहीं करेगा

  3. पार्स समय में एक [] निर्माण करें। चूंकि कोई नया डेटा संग्रहीत नहीं है (बाइट बफर में ऑफसेट के अलावा), पार्सिंग बहुत कम है कि # 1। समय मिलने पर, हमें एक स्ट्रिंग बनाने की आवश्यकता नहीं है, इसलिए प्रदर्शन # 1 के बराबर है (# 2 से बहुत बेहतर), क्योंकि हम केवल किसी मौजूदा ऑब्जेक्ट का संदर्भ दे रहे हैं।

चारसेंसेंस का उपयोग करके आपको प्राप्त होने वाले प्रोसेसिंग लाभ के अलावा, आप डेटा को डुप्लिकेट नहीं करके मेमोरी फ़ुटप्रिंट को भी कम करते हैं। उदाहरण के लिए, यदि आपके पास पाठ के 3 पैराग्राफ वाले बफ़र हैं, और सभी 3 या एकल पैराग्राफ को वापस करना चाहते हैं, तो आपको इसका प्रतिनिधित्व करने के लिए 4 स्ट्रिंग्स की आवश्यकता है। CharSequence का उपयोग करने के लिए आपको डेटा के साथ केवल 1 बफ़र की आवश्यकता होती है, और एक CharSequence कार्यान्वयन के 4 उदाहरण जो प्रारंभ और लंबाई को ट्रैक करते हैं।


6
संदर्भ plz बेतरतीब ढंग से लगता है कि क्या हो रहा है। यह भी कि मुझे आपका तर्क मान्य नहीं लगता। कोई बस पहली जगह में एक स्ट्रिंग के रूप में 500k बाइटबफ़र को स्टोर कर सकता है और बस सब्सट्रिंग लौटा सकता है, जो कि तेज़ तेज़ है, और बहुत अधिक सामान्य है।
kritzikratzi

6
@kritzikratzi - JDK7 के रूप में, स्ट्रिंग पर प्रतिस्थापन अब अंतर्निहित सरणी साझा नहीं करता है, और "पागल तेज़" नहीं है। सबस्टेशन की लंबाई में O (N) समय लगता है, और हर बार जब आप इसे कॉल करते हैं (तो बहुत सारा कचरा) अंतर्निहित वर्णों की एक प्रति उत्पन्न करता है।
BeeOnRope

@kritzikratzi मेरा मानना ​​है कि बदलाव का कारण यह है कि यदि कॉपी नहीं बनाई गई, तो मूल स्ट्रिंग को सभी सब्सट्रिंग्स के जीवनकाल के लिए बरकरार रखा जाएगा। यह देखते हुए कि आम तौर पर सबस्ट्रिंग मूल के केवल छोटे हिस्से होते हैं और अनिश्चित काल तक रह सकते हैं, यह इस बात पर निर्भर करता है कि उनका उपयोग कैसे किया जाता है, यह अक्सर अधिक कचरे का परिणाम होता है यदि मूल स्ट्रिंग की तुलना में सब्सट्रिंग बहुत लंबे समय तक उपयोग में थे। एक दिलचस्प ऊंचाई यह निर्धारित करने के लिए हो सकती है कि माता-पिता के स्ट्रिंग आकार के प्रतिस्थापन के अनुपात के आधार पर प्रतिलिपि बनाई जाए या नहीं, लेकिन आपको इसके लिए अपने स्वयं के CharSequenceकार्यान्वयन को रोल करना होगा ।
JAB

1
शायद मैं बिंदु से चूक गया हूं, लेकिन यह उत्तर बकवास है। A CharSequenceएक इंटरफ़ेस है - परिभाषा के अनुसार, इसमें आपके द्वारा चर्चा किए गए कार्यान्वयन विवरणों में से कोई भी नहीं है क्योंकि इसका अपना कोई कार्यान्वयन नहीं है । ए Stringकई ठोस वर्गों में से एक है जो CharSequenceइंटरफ़ेस को लागू करता है। तो एक String है एक CharSequence। आप Stringबनाम StringBufferबनाम के प्रदर्शन विवरण की तुलना कर सकते हैं StringBuilder, लेकिन नहीं CharSequence। "प्रसंस्करण लाभ जो आपको चारसेंसेंस का उपयोग करके मिलता है" लिखना व्यर्थ है।
बेसिल बॉर्क

7

एक मुद्दा जो व्यावहारिक एंड्रॉइड कोड में उत्पन्न होता है, वह है कि उनकी तुलना CharSequence.equals के साथ मान्य है, लेकिन यह आवश्यक रूप से काम नहीं करता है।

EditText t = (EditText )getView(R.id.myEditText); // Contains "OK"
Boolean isFalse = t.getText().equals("OK"); // will always return false.

द्वारा तुलना की जानी चाहिए

("OK").contentEquals(t.GetText()); 

5

CharSequence

A CharSequenceएक इंटरफ़ेस है, वास्तविक वर्ग नहीं। एक इंटरफ़ेस नियमों (विधियों) का एक सेट है जो एक वर्ग को शामिल करना चाहिए अगर वह इंटरफ़ेस को लागू करता है। एंड्रॉइड में CharSequenceविभिन्न प्रकार के टेक्स्ट स्ट्रिंग्स के लिए एक छाता है। यहाँ कुछ सामान्य हैं:

  • String (अपरिवर्तनीय पाठ जिसमें कोई स्टाइल नहीं है)
  • StringBuilder (कोई स्टाइल नहीं के साथ परस्पर पाठ)
  • SpannableString (स्टाइल स्पैन के साथ अपरिवर्तनीय पाठ)
  • SpannableStringBuilder (स्टाइलिंग स्पैन के साथ परस्पर पाठ)

(आप यहाँ इन दोनों के बीच अंतर के बारे में अधिक पढ़ सकते हैं ।)

यदि आपके पास कोई CharSequenceवस्तु है, तो यह वास्तव में लागू होने वाली कक्षाओं में से एक है CharSequence। उदाहरण के लिए:

CharSequence myString = "hello";
CharSequence mySpannableStringBuilder = new SpannableStringBuilder();

सामान्य छाता प्रकार होने का लाभ यह CharSequenceहै कि आप एक ही विधि से कई प्रकारों को संभाल सकते हैं। उदाहरण के लिए, अगर मेरे पास कोई ऐसा तरीका है जो CharSequenceएक पैरामीटर के रूप में लेता है , तो मैं एक Stringया एक में पास हो सकता हूं SpannableStringBuilderऔर यह एक को संभाल लेगा।

public int getLength(CharSequence text) {
    return text.length();
}

तार

आप कह सकते हैं कि एक Stringसिर्फ एक तरह का है CharSequence। हालांकि, इसके विपरीत CharSequence, यह एक वास्तविक वर्ग है, इसलिए आप इससे ऑब्जेक्ट बना सकते हैं। तो आप ऐसा कर सकते हैं:

String myString = new String();

लेकिन आप ऐसा नहीं कर सकते:

CharSequence myCharSequence = new CharSequence(); // error: 'CharSequence is abstract; cannot be instantiated

चूंकि CharSequenceनियमों की एक सूची है जो इसके Stringअनुरूप है, आप ऐसा कर सकते हैं:

CharSequence myString = new String();

इसका मतलब है कि किसी भी समय एक विधि के लिए पूछता है CharSequence, यह एक देने के लिए ठीक है String

String myString = "hello";
getLength(myString); // OK

// ...

public int getLength(CharSequence text) {
    return text.length();
}

हालांकि, विपरीत सच नहीं है। यदि विधि एक Stringपैरामीटर लेती है , तो आप इसे कुछ ऐसा नहीं कर सकते हैं जो केवल आम तौर पर एक के रूप में जाना जाता है CharSequence, क्योंकि यह वास्तव में SpannableStringया कुछ अन्य प्रकार का हो सकता है CharSequence

CharSequence myString = "hello";
getLength(myString); // error

// ...

public int getLength(String text) {
    return text.length();
}

0

CharSequenceएक इंटरफ़ेस है और Stringइसे लागू करता है। आप त्वरित कर सकते हैं Stringलेकिन आप ऐसा नहीं कर सकते CharSequenceक्योंकि यह एक इंटरफ़ेस है। आप CharSequenceआधिकारिक जावा वेबसाइट में अन्य कार्यान्वयन पा सकते हैं ।


-4

CharSequence चार मूल्यों का एक पठनीय अनुक्रम है जो स्ट्रिंग को लागू करता है। इसकी 4 विधियाँ हैं

  1. charAt (int index)
  2. लंबाई ()
  3. उप-अनुक्रम (इंट स्टार्ट, इंट एंड)
  4. तार()

देखें प्रलेखन CharSequence प्रलेखन


6
CharSequenceलागू नहीं करता है String। हालांकि यह सच है।
सेह

1
कृपया इस बकवास उत्तर को हटा दें
जे डो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.