दिलचस्प पोस्ट
जावा थ्रेड्स का उपयोग कर एकाधिक फ़ाइलों को डाउनलोड करें एक jQuery प्लगइन का विस्तार करने के लिए सबसे अच्छा तरीका वर्तमान निष्पादन विधि का नाम प्राप्त करें जेवीएम विकल्प -XSS – यह बिल्कुल क्या करता है? क्या IFrames (HTML) अप्रचलित हैं? यदि किसी ऐप को स्थापित किया गया है तो प्रोग्रामैटिक रूप से कैसे जांचें? फिक्स्ड पहली कॉलम के साथ बूटस्ट्रैप 3 उत्तरदायी तालिका ज़ूम कैनवास टू माउस कर्सर एचटीएमएल टैग को हटाने के लिए सी # रेगुलर एक्सप्रेशंस का उपयोग करना क्या ओपनसीएल प्रणाली बाएं हाथ या दाएं हाथ से समन्वय करता है? टॉमकेट में जड़ में अपने आवेदन को नियोजित करना jQuery के सत्यापन: डिफ़ॉल्ट त्रुटि संदेश बदलें UIImage iPhone पर फाइल नाम के साथ छवि को सहेज रहा है ggplot2: घनत्व वक्र के साथ ओवरले हिस्टोग्राम जीमेल एसएमटीपी सर्वर के माध्यम से सी # के साथ ईमेल भेजा जा रहा है

स्ट्रिंग लिटल पूल, स्ट्रिंग ऑब्जेक्ट, या ऑब्जेक्ट का एक संग्रह के संदर्भ का एक संग्रह है

मैं सभी को कोरी मैकग्लोन, द एससीजेपी टिप लाइन के लेखक, के जरूरंच साइट पर लेख पढ़ने के बाद उलझन में हूँ नाम स्ट्रिंग्स, शब्दशः और एससीजेपी जावा 6 प्रोग्रामर गाइड Kathy Sierra (co-founder of javaranch) and Bert Bates

मैं कहता हूं कि श्री कोरी और एमएस कैथी सिएरा ने स्ट्रिंग लिटरल पूल के बारे में उद्धृत किया है।

1. श्री कोरी मैकग्लोन के अनुसार:

  • स्ट्रिंग लिटरल पूल एक संदर्भ है जो स्ट्रिंग ऑब्जेक्ट को इंगित करता है।

  • String s = "Hello"; (मान लें कि "हेलो" नाम के ढेर पर कोई ऑब्जेक्ट नहीं है), ढेर पर एक स्ट्रिंग ऑब्जेक्ट "Hello" बनायेगा, और स्ट्रिंग लिटरल पूल (कॉन्स्टेंट टेबल) में इस ऑब्जेक्ट के लिए एक संदर्भ रखेगा।

  • String a = new String("Bye"); (मान लें कि "बाय" नामित ढेर पर कोई ऑब्जेक्ट नहीं है, new ऑपरेटर हीम पर ऑब्जेक्ट बनाने के लिए जेवीएम को उपकृत करेगा।

अब स्ट्रिंग और इसके संदर्भ के निर्माण के लिए "new" ऑपरेटर की व्याख्या इस लेख में थोड़ा भ्रमित है, इसलिए मैं लेख और स्पष्टीकरण को लेख से ही डाल रहा हूं क्योंकि यह नीचे है-

 public class ImmutableStrings { public static void main(String[] args) { String one = "someString"; String two = new String("someString"); System.out.println(one.equals(two)); System.out.println(one == two); } } 

इस मामले में, हम वास्तव में "new." कीवर्ड की वजह से थोड़ा अलग व्यवहार करते हैं "new." ऐसे मामले में, दो स्ट्रिंग लीटरल के संदर्भ अभी भी निरंतर तालिका (स्ट्रिंग लिटरल पूल) में डाल दिए जाते हैं, लेकिन जब आप "new," कीवर्ड पर आते हैं "new," तो JVM रन-रनिंग पर एक नया स्ट्रिंग ऑब्जेक्ट बनाने के लिए बाध्य है, निरंतर तालिका से एक का उपयोग करने के बजाय, समय।

यह चित्र समझा गया है ..

यहां छवि विवरण दर्ज करें

तो क्या इसका मतलब यह है कि स्ट्रिंग लिटरल पूल का भी इस उद्देश्य का संदर्भ है?

यहाँ कोरी मैकग्लोन द्वारा अनुच्छेद के लिए लिंक है

http://www.javaranch.com/journal/200409/Journal200409.jsp#a1

2. एससीजेपी बुक में कैथी सिएरा और बर्ट बेट्स के अनुसार:

  • जावा को और अधिक मेमोरी बनाने के लिए, जेवीएम ने एक विशेष क्षेत्र मेमोरी को "स्ट्रिंग स्टोरील पूल" नामक मेमोरी को एक तरफ सेट किया, जब कंपाइलर स्ट्रिंग लिटरल का सामना करता है, यह पूल को देखता है कि क्या एक समान स्ट्रिंग पहले से ही बाहर निकलती है या नहीं। यदि नहीं, तो यह एक नया स्ट्रिंग लिटरल ऑब्जेक्ट बनाता है।

  • String s = "abc"; // एक स्ट्रिंग वस्तु और एक संदर्भ चर बनाता है ….

    ठीक है, लेकिन अब नीचे दिए गए वक्तव्य में मुझे भ्रमित हो गया।

  • String s = new String("abc") // दो ऑब्जेक्ट्स, और एक संदर्भ चर बनाता है

    यह पुस्तक में कहते हैं कि …. सामान्य (गैर-पूल) मेमोरी में एक नया स्ट्रिंग ऑब्जेक्ट, और "एस" इसका उल्लेख करेंगे … जबकि एक अतिरिक्त "एबीसी" पूल में रखा जाएगा

    किताब में उपरोक्त पंक्तियाँ कोरी मैकग्लोन के लेख में से एक के साथ टकराती हैं

    • यदि स्ट्रिंग लीटरल पूल कोरी मैकग्लोन द्वारा वर्णित स्ट्रिंग ऑब्जेक्ट के संदर्भों का एक संग्रह है, तो पुस्तक में उल्लेखित के रूप में, "एबीसी" शब्द को पूल में कैसे रखा जाएगा।

    • और यह स्ट्रिंग लिटरल पूल कहां रहता है।

कृपया इस संदेह को साफ करें, हालांकि यह कोड लिखते समय बहुत ज्यादा मायने नहीं रखता, लेकिन मेमोरी प्रबंधन के पहलू से बहुत महत्वपूर्ण है, और इस कारण से मैं इस फंड को साफ़ करना चाहता हूं।

Solutions Collecting From Web of "स्ट्रिंग लिटल पूल, स्ट्रिंग ऑब्जेक्ट, या ऑब्जेक्ट का एक संग्रह के संदर्भ का एक संग्रह है"

मुझे लगता है कि मुख्य बिंदु को यहाँ समझना String जावा ऑब्जेक्ट और इसकी सामग्री – char[] निजी क्षेत्र के क्षेत्र के अंतर्गत char[] के बीच भेद है। String मूल रूप से char[] चारों ओर एक आवरण है, इसे ढाला जाता है और इसे संशोधित करना असंभव बनाते हैं ताकि String अपरिवर्तनीय रह सके। इसके अलावा String क्लास को यह याद रहता है कि इस सरणी के कौन सा हिस्से वास्तव में उपयोग किए गए हैं (नीचे देखें)। इसका मतलब यह है कि आपके पास दो अलग String ऑब्जेक्ट्स (काफी हल्के) हो सकते हैं जो एक ही char[] ओर इशारा करते हैं char[]

मैं आपको कुछ उदाहरण, प्रत्येक String और hashCode() के आंतरिक String char[] value फ़ील्ड के hashCode() के साथ दिखाऊंगा (मैं इसे स्ट्रिंग से अलग करने के लिए टेक्स्ट को कॉल करूंगा)। अंत में मैं अपने परीक्षण वर्ग के लिए लगातार पूल के साथ-साथ javap -c -verbose आउटपुट javap -c -verbose । कृपया स्ट्रिंग शाब्दिक पूल के साथ कक्षा लगातार पूल को भ्रमित न करें। वे काफी समान नहीं हैं कॉन्स्टेंट पूल के लिए जवाप के आउटपुट को समझना भी देखें

आवश्यक शर्तें

परीक्षण के प्रयोजन के लिए मैंने ऐसा एक ऐसी उपयोगिता पद्धति बनाई जो String इनकैप्सुलेशन को तोड़ देती है:

 private int showInternalCharArrayHashCode(String s) { final Field value = String.class.getDeclaredField("value"); value.setAccessible(true); return value.get(s).hashCode(); } 

यह char[] value hashCode() प्रिंट करेगा, प्रभावी ढंग से हमें यह समझने में मदद करता है कि क्या यह विशेष String एक ही char[] या char[] पाठ को इंगित करता है या नहीं।

एक कक्षा में दो स्ट्रिंग लीटरल

चलिए सरलतम उदाहरण से शुरू करते हैं।

जावा कोड

 String one = "abc"; String two = "abc"; 

बीटीडब्ल्यू यदि आप बस "ab" + "c" लिखते हैं, तो जावा कंपाइलर संकलन के समय में सम्मिलन करेगा और उत्पन्न कोड बिल्कुल वैसा ही होगा। यह केवल तभी काम करता है जब सभी तार संकलन समय पर ज्ञात होते हैं।

कक्षा स्थिर पूल

प्रत्येक वर्ग के पास अपना निरंतर पूल होता है – निरंतर मानों की एक सूची है जो फिर से उपयोग की जा सकती हैं यदि वे स्रोत कोड में कई बार होते हैं इसमें सामान्य स्ट्रिंग, नंबर, विधि नाम आदि शामिल हैं।

हमारे ऊपर के उदाहरण में लगातार पूल की सामग्री यहां दी गई है

 const #2 = String #38; // abc //... const #38 = Asciz abc; 

ध्यान देने योग्य बात यह है कि String निरंतर ऑब्जेक्ट ( #2 ) और यूनिकोड एन्कोडेड टेक्स्ट "abc" ( #38 ) के बीच अंतर यह है कि स्ट्रिंग को इंगित करता है।

बाइट कोड

यहां बाइट कोड उत्पन्न किया गया है। ध्यान दें कि दोनों one और two संदर्भ "abc" स्ट्रिंग के लिए इसी #2 निरंतर संकेत के साथ सौंपा गया है:

 ldc #2; //String abc astore_1 //one ldc #2; //String abc astore_2 //two 

उत्पादन

प्रत्येक उदाहरण के लिए मैं निम्नलिखित मानों को मुद्रित कर रहा हूं:

 System.out.println(showInternalCharArrayHashCode(one)); System.out.println(showInternalCharArrayHashCode(two)); System.out.println(System.identityHashCode(one)); System.out.println(System.identityHashCode(two)); 

कोई आश्चर्य नहीं कि दोनों जोड़े समान हैं:

 23583040 23583040 8918249 8918249 

इसका अर्थ है कि न केवल दोनों ऑब्जेक्ट एक ही char[] नीचे एक ही पाठ के नीचे char[] इंगित करते हैं) तो equals() परीक्षा पास हो जाएगी लेकिन और भी, one और two सटीक संदर्भ हैं! तो one == two भी सत्य है। जाहिर है, यदि one ही वस्तु को one और two अंक एक. one.value और two.value बराबर होना चाहिए।

आभासी और new String()

जावा कोड

अब हम सभी के लिए इंतजार कर रहे थे – एक स्ट्रिंग का शाब्दिक और एक नया String जिसका इस्तेमाल वही शाब्दिक है। ऐसे कैसे चलेगा?

 String one = "abc"; String two = new String("abc"); 

तथ्य यह है कि "abc" निरंतर स्रोत कोड में दो बार उपयोग किया जाता है आपको कुछ संकेत देना चाहिए …

कक्षा स्थिर पूल

ऊपर की तरह।

बाइट कोड

 ldc #2; //String abc astore_1 //one new #3; //class java/lang/String dup ldc #2; //String abc invokespecial #4; //Method java/lang/String."<init>":(Ljava/lang/String;)V astore_2 //two 

ध्यान से देखिए! पहला ऑब्जेक्ट ऊपर जैसा ही बनाया गया है, कोई आश्चर्य नहीं। यह निरंतर पूल से पहले से निर्मित String ( #2 ) के लिए एक निरंतर संदर्भ लेता है हालांकि दूसरा ऑब्जेक्ट सामान्य कंस्ट्रक्टर कॉल के माध्यम से बनाया गया है। परंतु! पहली String एक तर्क के रूप में पारित की जाती है इसे कमजोर किया जा सकता है:

 String two = new String(one); 

उत्पादन

उत्पादन थोड़ा आश्चर्य की बात है। String ऑब्जेक्ट के संदर्भ का प्रतिनिधित्व करने वाला दूसरा जोड़ी समझा जा सकता है- हमने दो String ऑब्जेक्ट्स बनाए हैं – एक हमारे लिए लगातार पूल में बनाया गया था और दूसरा मैन्युअल रूप से two लिए मैन्युअल रूप से बनाया गया था लेकिन क्यों, धरती पर पहली जोड़ी से पता चलता है कि दोनों String ऑब्जेक्ट्स एक ही char[] value सरणी को इंगित करते हैं ?!

 41771 41771 8388097 16585653 

यह स्पष्ट हो जाता है जब आप String(String) कन्स्ट्रक्टर कैसे काम करते हैं (यहां पर बहुत सरलीकृत) देखें:

 public String(String original) { this.offset = original.offset; this.count = original.count; this.value = original.value; } 

देख? जब आप मौजूदा एक के आधार पर नया String ऑब्जेक्ट बना रहे हैं, तो यह char[] value reuses String अपरिवर्तनीय हैं, डेटा संरचना को कॉपी करने की कोई आवश्यकता नहीं है जिसे कभी भी संशोधित नहीं किया जाता है।

मुझे लगता है कि यह आपकी समस्या का सुराग है: भले ही आपके पास दो String ऑब्जेक्ट हैं, वे अभी भी उसी सामग्री को इंगित कर सकते हैं और जैसा कि आप देख सकते हैं कि String ऑब्जेक्ट ही काफी छोटा है

रनटाइम संशोधन और intern()

जावा कोड

मान लें कि आपने शुरू में दो अलग-अलग स्ट्रिंग्स का इस्तेमाल किया था लेकिन कुछ संशोधनों के बाद वे सभी समान हैं:

 String one = "abc"; String two = "?abc".substring(1); //also two = "abc" 

जावा कंपाइलर (कम से कम मेरा) संकलन के समय इस तरह के संचालन को करने के लिए पर्याप्त चतुर नहीं है, एक नज़र रखें:

कक्षा स्थिर पूल

अचानक हम दो निरंतर स्ट्रिंग्स के साथ समाप्त हो गए जो कि दो अलग-अलग निरंतर पाठों की ओर इशारा करते हैं:

 const #2 = String #44; // abc const #3 = String #45; // ?abc const #44 = Asciz abc; const #45 = Asciz ?abc; 

बाइट कोड

 ldc #2; //String abc astore_1 //one ldc #3; //String ?abc iconst_1 invokevirtual #4; //Method String.substring:(I)Ljava/lang/String; astore_2 //two 

मुट्ठी की स्ट्रिंग हमेशा की तरह निर्माण की जाती है। दूसरा, पहले "?abc" स्ट्रिंग को निरंतर लोड करके बनाया जाता है और फिर उस पर substring(1) को कॉल करता है

उत्पादन

यहां कोई आश्चर्य नहीं है – हमारे पास दो अलग-अलग तार हैं, जो स्मृति में दो अलग-अलग char[] ग्रंथों char[] ओर इशारा करता है:

 27379847 7615385 8388097 16585653 

खैर, ग्रंथ वास्तव में भिन्न नहीं हैं, equals() विधि अभी भी true उत्पन्न करेगी। हमारे पास एक ही पाठ की दो अनावश्यक प्रतियां हैं

अब हमें दो अभ्यास चलाने चाहिए सबसे पहले, चलने का प्रयास करें:

 two = two.intern(); 

मुद्रण हैश कोड से पहले न केवल one ही पाठ के लिए दोनों one और two बिंदु, लेकिन वे एक ही संदर्भ हैं!

 11108810 11108810 15184449 15184449 

इसका मतलब ये है कि दोनों एक। one.equals(two) और one == two परीक्षण पारित होंगे। इसके अलावा हमने कुछ मेमोरी बचाई क्योंकि "abc" पाठ मेमोरी में केवल एक बार प्रकट होता है (दूसरी प्रतिलिपि कचरा एकत्रित हो जाएगी)।

दूसरा अभ्यास थोड़ा अलग है, इसे देखें:

 String one = "abc"; String two = "abc".substring(1); 

जाहिर है one और two दो अलग-अलग वस्तुएं हैं, जो कि दो अलग-अलग ग्रंथों की ओर इशारा करते हैं। लेकिन आउटपुट कैसे पता चलता है कि वे दोनों एक ही char[] सरणी char[] इंगित करते हैं?!?

 23583040 23583040 11108810 8918249 

मैं आपको जवाब छोड़ दूँगा यह आपको substring() कि कैसे substring() काम करता है substring() काम करता है, इस तरह के दृष्टिकोण के फायदे क्या हैं और जब यह बड़ी मुश्किलें पैदा कर सकता है।