سلسلة ثابتة في جافا
هناك نوعان من إنشاء كائن السلسلة في Java. واحد هو شكل حرفي ، مثل String str = "droid" ؛ والآخر هو طريقة قياسية لإنشاء كائنات باستخدام جديد ، مثل String Str = New String ("Droid") ؛. غالبًا ما نستخدم هاتين الطريقتين عند كتابة التعليمات البرمجية ، وخاصة الطريقة الحرفية. ومع ذلك ، فإن هذين التنفيذيين لديهما بعض الاختلافات في الأداء واستخدام الذاكرة. كل هذا يرجع إلى حقيقة أن JVM يحافظ على ذاكرة خاصة من أجل تقليل إنشاء كائنات السلسلة المتكررة ، وهو تجمع ثابت للسلسلة أو تجمع حرفي للسلسلة.
كيف تعمل
عند إنشاء كائن سلسلة في النموذج الحرفي في الكود ، سيقوم JVM أولاً بفحص الحرفي. إذا كان هناك مرجع إلى كائن سلسلة مع نفس المحتوى في تجمع السلسلة الثابت ، فسيتم إرجاع المرجع. خلاف ذلك ، سيتم إنشاء كائن السلسلة الجديد ، ثم يتم وضع المرجع في تجمع السلسلة الثابت وسيتم إرجاع المرجع.
إعطاء مثال
شكل الخلق الحرفي
String str1 = "droid" ؛
يكتشف JVM هذا الحرفي ، وهنا نعتقد أنه لا يوجد كائن مع محتوى موجود. لا يمكن لـ JVM العثور على كائن السلسلة مع محتوى droid من خلال تجمع السلسلة الثابت ، لذلك سيقوم بإنشاء كائن السلسلة هذا ، ثم وضع مرجع الكائن الذي قمت بإنشائه للتو في تجمع ثابت ، وإرجاع المرجع إلى Str1 المتغير.
إذا كان هناك رمز مثل هذا التالي
String str2 = "droid" ؛
وبالمثل ، لا يزال JVM بحاجة إلى اكتشاف هذا الحرفي. من خلال البحث عن تجمع ثابت للسلسلة ، وجد JVM أن المحتوى هو كائن سلسلة "droid" موجود ، لذلك يرجع مرجع كائن السلسلة الموجود إلى STR2 المتغير. لاحظ أنه لن يتم إعادة إنشاء كائنات سلسلة جديدة هنا.
تحقق مما إذا كان STR1 و Str2 يشيران إلى نفس الكائن ، يمكننا استخدام هذا الرمز
system.out.println (str1 == str2) ؛
النتيجة صحيحة.
إنشاء مع جديد
String str3 = سلسلة جديدة ("droid") ؛
عندما نستخدم جديدة لبناء كائنات سلسلة ، سيتم إنشاء كائنات سلسلة جديدة بغض النظر عما إذا كانت هناك إشارات إلى كائنات ذات نفس المحتوى في المجموعة الثابتة. لذلك دعونا نستخدم الكود التالي لاختباره.
String str3 = سلسلة جديدة ("droid") ؛
System.out.println (str1 == Str3) ؛
والنتيجة خاطئة كما نعتقد ، مما يشير إلى أن المتغيرين يشيران إلى كائنات مختلفة.
المتدرب
بالنسبة لكائن السلسلة الذي تم إنشاؤه باستخدام جديد أعلاه ، إذا كنت ترغب في إضافة مرجع إلى تجمع String الثابت ، يمكنك استخدام طريقة المتدرب.
بعد استدعاء المتدرب ، تحقق أولاً مما إذا كان هناك إشارة إلى الكائن في المجموعة الثابتة. إذا كان موجودًا ، فأرجع هذا المرجع إلى المتغير ، وإلا سيتم إضافة المرجع وإعادته إلى المتغير.
String str4 = str3.intern () ؛
System.out.println (str4 == Str1) ؛
نتيجة الإخراج صحيحة.
مشاكل صعبة
المتطلبات الأساسية؟
المتطلب السابق لتنفيذ تجمعات ثابتة للسلسلة هو أن كائنات السلسلة في Java غير قابلة للتغيير ، والتي يمكن أن تضمن بأمان أن متغيرات متعددة تشترك في نفس الكائن. إذا كان كائن السلسلة في Java متغيرًا ، وتغيير عملية مرجعية واحدة من قيمة الكائن ، فستتأثر أيضًا متغيرات أخرى ، من الواضح أن هذا غير معقول.
المرجع أو الكائن
يكون هذا السؤال أكثر شيوعًا عند تخزين تجمع ثابت للسلسلة في مرجع أو كائن. يقوم سلسلة البركة الثابتة بتخزين مراجع كائن ، وليس الكائنات. في Java ، يتم إنشاء الكائنات في ذاكرة الكومة.
تحديث التحقق ، العديد من التعليقات التي تم تلقيها تناقش أيضًا هذه المشكلة ، وأنا ببساطة أتحقق منها. تحقق من البيئة
22: 18: 54-androidyue ~/videos $ cat/etc/os-releasename = fedoraversion = "17 (Bepy Miracle)" id = fedoraversion_id = 17pretty_name = "fedora 17 (befyy معجزة) "ansi_color =" 0 ؛ 34 "cpe_name =" cpe:/o: fedoraproject: fedora: 17 "22: 19: 04-androidyue ~/videos $ java -ventjava version" 1.7.0_25 VM (بناء 23.7-B01 ، وضع مختلط)
فكرة التحقق: يقرأ برنامج Java التالي ملف فيديو بحجم 82 مترًا ويؤدي عمليات متدربة في شكل سلسلة.
22: 01: 17 -Androidyue ~/videos $ ll -lh | GREP WHY_TO_LEARN.MP4-RW-RW-R--. 1 Androidyue Androidyue 82m Oct 20 2013 why_to_learn.mp4
رمز التحقق
استيراد java.io.bufferedreader ؛ استيراد java.io.filenotfoundException ؛ استيراد java.io.filereader ؛ استيراد java.io.ioException ؛ فئة عامة testmain {private static string fileContent ؛ الفراغ الثابت العام (سلسلة [] args) {fileContent = readFiLetoString (args [0]) ؛ if (null! = fileContent) {fileContent = fileContent.intern () ؛ System.out.println ("not null") ؛ }} سلسلة ثابتة readFiLetoString (ملف السلسلة) {bufferedReader reader = null ؛ Try {reader = new BufferEdReader (New FileReader (file)) ؛ StringBuffer Buff = new StringBuffer () ؛ خط السلسلة بينما ((line = reader.ReadLine ())! = null) {buff.append (line) ؛ } return buff.toString () ؛ } catch (fileNotFoundException e) {e.printStackTrace () ؛ } catch (ioException e) {E.PrintStackTrace () ؛ } أخيرًا {if (null! = reader) {try {reader.close () ؛ } catch (ioException e) {E.PrintStackTrace () ؛ }}} return null ؛ }}نظرًا لوجود تجمع ثابت للسلسلة في الجيل الدائم في ذاكرة الكومة ، فهو مناسب قبل Java 8. نتحقق من خلال تحديد جيل دائم من القيمة الصغيرة. إذا كان كائن السلسلة موجودًا في المجموعة الثابتة للسلسلة ، فيجب إلقاء خطأ java.lang.outofmemoryerror permgen.
java -xx: permsize = 6m testmain ~/videos/why_to_learn.mp4
تشغيل برنامج الإثبات لا يرمي OOM ، ولكن هذا لا يمكن أن يثبت أنه يتم تخزينه ككائن أو مرجع.
ولكن هذا يثبت على الأقل أن كائن المحتوى الفعلي char [] للسلسلة لا يتم تخزينه في مجموعة ثابتة السلسلة. في هذه الحالة ، ليس من المهم للغاية أن يقوم مجموعة التجمع الثابتة بتخزين الإشارات إلى كائنات السلسلة أو كائنات السلسلة. لكن الأفراد ما زالوا يميلون إلى تخزين المراجع.
إيجابيات وسلبيات
تتمثل ميزة التجميع الثابت في سلسلة إنشاء سلاسل من نفس المحتوى وحفظ مساحة الذاكرة.
إذا كان عليك أن تقول العيوب ، فهذا هو التضحية بوقت حساب وحدة المعالجة المركزية لتبادل مساحة. يتم استخدام وقت حساب وحدة المعالجة المركزية بشكل أساسي للعثور على ما إذا كانت هناك إشارات إلى كائنات ذات نفس المحتوى في تجمع String الثابت. ومع ذلك ، فإن تنفيذها الداخلي قابلة للتصنيف ، وبالتالي فإن تكلفة الحساب منخفضة.
إعادة تدوير GC؟
نظرًا لأن تجمع السلسلة الثابت يحمل مرجعًا إلى كائن السلسلة المشتركة ، فهل هذا يعني أنه لا يمكن إعادة تدوير هذه الكائنات؟
بادئ ذي بدء ، تكون الكائنات المشتركة في السؤال أصغر بشكل عام. بقدر ما تحققت ، كانت هناك بالفعل مشكلة في الإصدارات السابقة ، ولكن مع إدخال المراجع الضعيفة ، يجب أن تكون هذه المشكلة في الوقت الحاضر.
فيما يتعلق بهذه المشكلة ، يمكنك معرفة المزيد حول هذه المقالة. السلاسل الداخلية: جافا مسرد
استخدم المتدرب؟
الشرط المسبق لاستخدام المتدرب هو أنك تعلم أنك تحتاج حقًا إلى استخدامه. على سبيل المثال ، لدينا سجل من الملايين هنا ، حيث تكون قيمة معينة من السجل هي كاليفورنيا ، الولايات المتحدة الأمريكية عدة مرات. لا نريد إنشاء ملايين كائنات السلسلة هذه. يمكننا استخدام المتدرب للحفاظ على نسخة واحدة فقط في الذاكرة. للحصول على فهم أكثر تعمقا للمتدرب ، يرجى الرجوع إلى التحليل المتعمق للسلسلة#المتدرب.
هل هناك دائما استثناءات؟
هل تعرف أن الكود التالي سيقوم بإنشاء العديد من كائنات السلسلة ويحفظ عدة مراجع في تجمع String Constant؟
String test = "A" + "B" + "C" ؛
الجواب هو أنه يتم إنشاء كائن واحد فقط ويتم حفظ مرجع واحد فقط في التجمع الثابت. نحن نستخدم فك تشويش جافاب ونلقي نظرة عليه.
17:02 $ JAVAP -C TestinternedPoolgCcompiled من "TestinternedPoolgc.java" TestinternedPoolGC يمتد Java.lang.Object {public testinterdpoolgc () ؛ الكود: 0: aload_0 1: invokespecial #1 ؛ // الطريقة java/lang/object. الكود: 0: LDC #2 ؛ // String ABC 2: Store_1 3: Returnهل رأيته؟ في الواقع ، خلال فترة التجميع ، تم تصنيع هذه الحرفية الثلاثة في واحدة. هذا هو في الواقع تحسين يتجنب إنشاء كائنات سلسلة زائدة عن الحاجة وليس لديها مشاكل خياطة السلسلة. لخياطة السلسلة ، يمكنك عرض تفاصيل Java: خياطة خيط.
ما سبق هو عبارة عن مجموعة من المعلومات المتعلقة بتجمعات سلسلة ثابتة في Java. سنستمر في إضافة المعلومات ذات الصلة في المستقبل. شكرا لك على دعمك لهذا الموقع!