دعونا نفكر في سؤال حول السلسلة في Java: الفرق بين "ABC" + '/' و "ABC" + "/". من خلال هذا المثال ، يمكننا ممارسة استخدام Javap في أدوات JDK. السؤال الأصلي هو كما يلي:
ما هو الفرق بين علاج القطع المائلة/كحرف أو سلاسل؟
يتم استخدام واحد كنوع البيانات الأساسي ، والآخر هو سلسلة الكائن. ما هو الفرق المحدد؟
هل سيكون أكثر كفاءة في معاملته كشخصية؟
String str = "ABC" + '/' ؛
و
String str = "ABC" + "/" ؛
1. التحسين المترجم
بادئ ذي بدء ، يجب أن تعلم أن الجملتين أعلاه لهما نفس التأثير ، لأن المترجم سيقوم بتحسين الجملتين أعلاه إلى ما يلي:
String str = "ABC/" ؛
يمكننا إثبات هذا من خلال جافاب. بالنسبة لـ Javap ، يمكننا الرجوع إلى "5 أدوات JDK التي يجب على كل مطور Java معرفته". نقوم أولاً بإنشاء فئة: Stringone ، وملء الكود التالي في الطريقة الرئيسية:
StringOne.javastring str1 = "abc" + '/' ؛ String str2 = "abc" + "/" ؛ shestem.out.println(str1 == str2) ؛
ترجمة وتشغيل ، نتيجة الإخراج صحيحة. بعد ذلك ، تم إطلاق Javap الخاص بنا ، أدخل الأمر التالي في سطر الأوامر:
javap -v -l stringone.class> stringone.s
ثم تحقق من ملف stringone.s الذي تم إنشاؤه. ستجد أن هناك عدة خطوط فيه
Stringone.s #2 = String #20 // ABC /...# 20 = UTF8 ABC/... 0: LDC #2 // String ABC/2: Store_13: LDC #2 // String ABC/5: store_2
Explanation: يشير STR1 و STR2 إلى السلسلة "ABC/".
2. استخدم جافاب لتحليل الاختلافات
الآن دعونا نغير السؤال. ما هو الفرق بين أساليب StringAddString و StringAddchar في الكود التالي؟
StringTwopublic static String StringAddString (String str1 ، String str2) {return str1 + str2 ؛} string stringdchar stringdchar (String str ، char ch) {return str + ch ؛}هذه المرة ، يتم استخدام javap لإلغاء التجميع ، وبعض محتويات الملف الذي تم إنشاؤه هي كما يلي
Stringtwo.spublic Java.lang.String StringAddString (java.lang.string ، java.lang.string) ؛ واصف: (ljava/lang/string ؛ ljava/lang/string ؛) ljava/lang/string ؛ الأعلام: ACC_Public Code: stack = 2 ، السكان المحليون = 3 ، args_size = 3 0: جديد #2 // class java/lang/stringbuilder 3: dup 4: invokespecial #3 // method java/lang/stringbuilder. إلحاق: (ljava/lang/string ؛) ljava/lang/stringBuilder ؛ 11: aload_2 12: InvokeVirtual #4 // Method Java/Lang/StringBuilder. إلحاق: (ljava/lang/string ؛) ljava/lang/stringBuilder ؛ 15: InvokeVirtual #5 // Method Java/Lang/StringBuilder. tostring :() ljava/lang/string ؛ 18: areturnpublic java.lang.String StringAddchar (java.lang.string ، char) ؛ واصف: (ljava/lang/string ؛ c) ljava/lang/string ؛ الأعلام: ACC_Public Code: stack = 2 ، السكان المحليون = 3 ، args_size = 3 0: جديد #2 // class java/lang/stringbuilder 3: dup 4: invokespecial #3 // method java/lang/stringbuilder. java/lang/stringbuilder.append: (ljava/lang/string ؛) ljava/lang/stringBuilder ؛ 11: ILOAD_2 12: InvokeVirtual #6 // الطريقة java/lang/stringbuilder.append: (c) ljava/lang/stringbuilder ؛ 15: invokevirtual #5 // الطريقة java/lang/stringbuilder.toString :() ljava/lang/string ؛ 18: أريتورن
الآن ، يمكننا أن نرى بوضوح عملية تنفيذ هاتين الطريقتين:
StringAddString
إن إجراء StringAddchar هو نفسه StringAddString ، باستثناء أنه عندما تسمى طريقة الإلحاق في المرة الثانية ، تكون معلمة StringAddString من نوع السلسلة ، في حين أن معلمة StringAddchar من نوع Char.
3. طريقة إلحاق (char) وطريقة إلحاق (سلسلة) من فئة StringBuilder
هنا ، نحتاج فقط إلى التحقق من رمز المصدر مباشرة (الألغام هو الرمز المصدر الذي يأتي مع JDK1.8.0_60). لاحظ أنه على الرغم من أن المستند يوضح أن StringBuilder يرث من كائن ، من الكود المصدر ، فإنه ورثته من الفئة المجردة AbstractStringBuilder. ويتم تنفيذ طريقة الإلحاق بواسطة AbstractStringBuilder.
AbstractStringBuilder.java
Public AbstractStringBuilder Aspend (char c) {insureCapacityInternal (count + 1) ؛ // تأكد من أن الصفيف يمكن أن يستوعب قيمة+1 أحرف [count ++] = c ؛ إرجاع هذا ؛} Public AbstractStringBuilder Aspend (String str) {if (str == null) return appendnull () ؛ int len = str.length () ؛ insureCapacityInternal (count + len) ؛ str.getchars (0 ، len ، value ، count) ؛ // انسخ صفيف الأحرف في السلسلة في صفيف الأحرف من عدد الكائن هذا += LEN ؛ أعد هذا ؛}لن يتم نشر الباقي بعد الآن. string.getChars (int ، int ، char [] ، int) يعتمد في النهاية على arraycopy الفراغ الأصلي الثابت (الكائن ، int ، الكائن ، int ، int). بمعنى آخر ، قد تكون مكتوبًا بلغة C ، ويجب أن تكون الكفاءة أفضل عند نسخ المصفوفات الكبيرة من البرامج المكتوبة في Java. لذا ، دعني أخبرك الآن بما أفهمه:
من حيث الذاكرة المباشرة ، نظرًا لأن السلسلة تحتوي على صفائف Char ، يجب أن يكون للمصفوفة حقول طول. في الوقت نفسه ، تحتوي فئة السلسلة على خاصية تجزئة INT ، وسيشغل الكائن نفسه ذاكرة إضافية لتخزين معلومات أخرى ، وبالتالي ستشغل السلسلة المزيد من الذاكرة. ومع ذلك ، إذا كانت السلسلة طويلة جدًا ، فيمكن تقريبًا تجاهل هذه النفقات العامة للذاكرة ؛ وإذا كانت السلسلة قصيرة (جدًا) ، فمن المحتمل جدًا أن تكون هناك العديد من المراجع المشتركة لمشاركة هذه الذاكرة النفقات العامة ، لذلك لا يزال من الممكن تجاهل النفقات الزائدة للذاكرة.
من مكدس المكالمات ، نظرًا لأن السلسلة تحتوي فقط على مكالمات وظيفية أخرى أكثر من char هنا ، إذا لم يتم النظر في النفقات العامة لدعوة الوظيفة (بما في ذلك الوقت والمكان) ، فيجب أن تكون متشابهة ؛ إذا تم اعتبار الدالة النفقات العامة ، يجب أن تكون "ABC" + "/" أفضل ؛ ولكن عندما تحتاج العديد من الأحرف إلى التواصل (أعتقد أن هذا الموقف يجب أن يكون أكثر شيوعًا ، أليس كذلك؟) ، لأن استخدام Char يتطلب العديد من الحلقات لإكمال الاتصال ، فإن عدد الوظائف المسمى فقط أكثر من استخدام السلسلة. في الوقت نفسه ، لن يكون النسخ أسرع من سلسلة نسخ مجموعة مباشرة. لذلك في هذا الوقت ، يصبح "ABC" + "/" مع إنتاجية أكبر.
الآن أشعر أن هذا السؤال يسأل: هل من أكثر كفاءة استخدام مكالمات النظام عند قراءة الملفات وكتابةها ، أو هل من أكثر كفاءة استخدام مكتبة IO في مكتبة الوظائف القياسية. أنا شخصياً أشعر أنه على الرغم من أن مكتبة IO القياسية يجب أن تستدعي مكالمات النظام في النهاية ، وسيتم إنشاء بعض المتغيرات المؤقتة ومكدس المكالمات الأعمق ، نظرًا لآليات التخزين المؤقت لمكتبة IO ، فإن إنتاجية مكتبة IO ستكون أكبر ، وسيكون الأداء في الوقت الفعلي لمكالمات النظام أفضل. وبالمثل ، على الرغم من أن فئة السلسلة سيكون لها المزيد من الحقول ومكدس وظيفة أعمق ، يجب أن تكون الإنتاجية أفضل بسبب ذاكرة التخزين المؤقت والنسخ المباشر.
أسئلة جديدة
انطلاقًا من رمز فك Javap أعلاه ، عند إضافة سلسلتين معًا ، ستصبح سلاسل إلحاق في StringBuilder. لذلك ، من الناحية النظرية ، أي من الكود التالي أكثر كفاءة؟
String str1 = "ABC" + "123" ؛ // 1StringBuilder StringBuilder = new StringBuilder () ؛ // 2StringBuilder.Append ("ABC") ؛ StringBuilder.Append ("123") ؛ String str2 = StringBuilder.toString () ؛دع هذا السؤال يترك للجميع للتفكير!
ما سبق هو كل محتوى هذه المقالة ، مما يساعدك على تمييز سلسلة+سلسلة وسلسلة+char في Java بشكل أفضل. آمل أن يكون ذلك مفيدًا لتعلم الجميع.