لماذا لا السلاسل تكون قابلة للتغيير في جاوة .الشبكة ؟

StackOverflow https://stackoverflow.com/questions/93091

  •  01-07-2019
  •  | 
  •  

سؤال

لماذا هو أنها قررت أن تجعل سلسلة ثابتة في جاوة .صافي (وبعض اللغات الأخرى)?لماذا لم تجعلها قابلة للتغيير?

هل كانت مفيدة؟

المحلول

وفقا فعالة جافا, الفصل 4, صفحة 73, 2nd edition:

"هناك العديد من الأسباب الوجيهة لهذا:ثابتة الطبقات أسهل تصميم وتنفيذ واستخدام قابلة للتغيير من الطبقات.هم أقل عرضة الخطأ أكثر أمنا.

[...]

"ثابتة كائنات بسيطة. كائن غير قابل للتغيير يمكن أن يكون في واحد بالضبط الدولة ، الدولة التي أنشئت من أجلها.إذا كان عليك التأكد من أن جميع المنشئات إنشاء فئة الثوابت ، فمن ضمان أن هذه الثوابت سوف يظل صحيحا بالنسبة لجميع الوقت ، أي جهد على الجزء الخاص بك.

[...]

ثابتة الأشياء بطبيعتها موضوع آمنة;أنها لا تتطلب المزامنة. أنها لا يمكن أن تكون تالفة من قبل العديد من المواضيع الحصول عليها في وقت واحد.هذا أسهل النهج إلى تحقيق سلامة الموضوع.في الواقع, أي خيط يمكن من أي وقت مضى مراقبة أي تأثير آخر موضوع على كائن غير قابل للتغيير.لذلك ، ثابتة الكائنات يمكن أن تكون مشتركة بحرية

[...]

غيرها من نقاط صغيرة من نفس الفصل:

ليس فقط يمكنك مشاركة ثابتة الكائنات ، ولكن يمكنك تبادل الداخلية.

[...]

ثابتة كائنات رائعة لبنات الكائنات الأخرى ، سواء كانت قابلة للتغيير أو غير قابل للتغيير.

[...]

العيب الحقيقي الوحيد ثابتة الطبقات هو أنها تتطلب كائن منفصل لكل قيمة متميزة.

نصائح أخرى

هناك سببين على الأقل.

أولا - الأمن http://www.javafaq.nu/java-article1060.html

السبب الرئيسي وراء سلسلة مصنوعة ثابتة كان الأمن.أنظر إلى هذا على سبيل المثال:لدينا طريقة فتح الملف مع الاختيار تسجيل الدخول.ونحن تمرير سلسلة هذه الطريقة عملية المصادقة وهو أمر ضروري قبل الدعوة سيتم تمريرها إلى نظام التشغيل.إذا كانت السلسلة قابلة للتغيير كان من الممكن بطريقة ما تعديل محتواه بعد الاختيار مصادقة من قبل نظام التشغيل يحصل طلب من البرنامج ثم هو ممكن طلب أي ملف.حتى إذا لديك الحق في فتح ملف نصي في دليل المستخدم لكن على الطاير عندما بطريقة ما تمكنوا من تغيير اسم الملف يمكنك طلب فتح "passwd" ملف أو أي شيء آخر.ثم يمكن تعديل ملف وسيكون من الممكن تسجيل الدخول مباشرة إلى نظام التشغيل.

ثانيا - الذاكرة الكفاءة http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html

JVM داخليا يحافظ على "سلسلة التجمع".لتحقيق الذاكرة الكفاءة JVM بإحالة السلسلة كائن من حوض السباحة.وسوف يتم إنشاء السلسلة الجديدة الكائنات.لذا ، كلما يمكنك إنشاء سلسلة جديدة الحرفي ، JVM سوف تحقق في حوض السباحة سواء كان موجود بالفعل أم لا.إذا بالفعل موجودة في البركة فقط تعطي إشارة إلى نفس الكائن أو إنشاء كائن جديد في حوض السباحة.سيكون هناك أن العديد من الإشارات تشير إلى نفس سلسلة الكائنات ، إذا كان شخص ما يتغير التي سوف تؤثر على جميع المراجع.لذا الشمس قررت أن تجعل من غير قابل للتغيير.

في الحقيقة الأسباب السلسلة هي ثابتة في جافا ليس لديها الكثير لتفعله مع الأمن.اثنين من الأسباب الرئيسية هي كما يلي:

Thead السلامة:

سلاسل للغاية على نطاق واسع نوع الكائن.ولذلك أكثر أو أقل مضمونة لاستخدامها في مجموعة متعددة الخيوط البيئة.سلاسل ثابتة للتأكد من أنها آمنة لتبادل السلاسل بين المواضيع.وجود ثابتة سلاسل يضمن أنه عندما يمر سلاسل من موضوع إلى موضوع آخر ب الموضوع ب لا يمكن بشكل غير متوقع تعديل الخيط هو الخيط.

وهذا لا يساعد فقط تبسيط بالفعل معقدة جدا مهمة متعددة الخيوط البرمجة ، ولكنه يساعد أيضا مع أداء تطبيقات متعددة الخيوط.الوصول إلى كائنات قابلة للتغيير يجب بطريقة أو بأخرى أن تكون متزامنة عندما يمكن الوصول إليها من خيوط متعددة ، للتأكد من أن مؤشر واحد لا تحاول قراءة قيمة من وجوه الخاص بك بينما يتم تعديلها من قبل مؤشر ترابط آخر.تزامن المناسبة سواء من الصعب القيام به بشكل صحيح مبرمج و مكلفة في وقت التشغيل.ثابتة الأشياء لا يمكن تعديل وبالتالي لا تحتاج إلى التزامن.

الأداء:

في حين سلسلة تتدرب وقد ذكر أنها لا تمثل سوى مكاسب صغيرة في الذاكرة كفاءة برامج جافا.فقط سلسلة حرفية يتم اعتقالهم.وهذا يعني أن السلاسل التي هي نفسها في التعليمات البرمجية المصدر سوف تتقاسم نفس الكائن سلسلة.إذا كان البرنامج حيوي يخلق السلسلة التي هي نفسها, أنها سوف تكون ممثلة في كائنات مختلفة.

والأهم من ذلك ثابتة سلاسل تسمح لهم لتبادل البيانات الداخلية.العديد من سلسلة من العمليات ، وهذا يعني أن وراء مجموعة من الشخصيات لا تحتاج إلى أن يتم نسخها.على سبيل المثال لنفترض أنك تريد أن تأخذ الخمسة الأحرف الأولى من السلسلة.في جافا, كنت المكالمات myString.فرعية(0,5).في هذه الحالة, ما substring() الأسلوب هو ببساطة إنشاء سلسلة جديدة الكائن الذي أسهم myString الأساسية char[] ولكن الذي يعرف أن يبدأ في الفهرس 0 وينتهي في الفهرس 5 من char[].لوضع هذا في شكل رسوم بيانية ، كنت في نهاية المطاف مع ما يلي:

 |               myString                  |
 v                                         v
"The quick brown fox jumps over the lazy dog"   <-- shared char[]
 ^   ^
 |   |  myString.substring(0,5)

وهذا ما يجعل هذا النوع من العمليات رخيصة للغاية ، س(1) منذ العملية لا يعتمد على طول السلسلة الأصلية ، ولا على طول فرعية نحن بحاجة إلى استخراج.هذا السلوك أيضا بعض المنافع الذاكرة ، لأن العديد من سلاسل تستطيع المشاركة الأساسية char[].

موضوع السلامة والأداء.إذا سلسلة لا يمكن تعديل أنها آمنة و سريعة لتمرير إشارة حولها بين مؤشرات ترابط متعددة.إذا كانت السلاسل قابلة للتغيير, سيكون لديك دائما إلى نسخ كل بايت من السلسلة إلى مثيل جديد ، أو التزامن.تطبيق نموذجي قراءة سلسلة 100 مرة في كل مرة أن سلسلة يحتاج إلى تعديل.انظر ويكيبيديا ثبات.

واحد حقا ينبغي أن تسأل: "لماذا يجب X تكون قابلة للتغيير?" فمن الأفضل الافتراضي إلى ثبات ، بسبب الفوائد التي سبق ذكرها الأميرة زغب.ينبغي أن يكون استثناء شيء غير قابلة للتغيير.

للأسف معظم الحالية لغات البرمجة الافتراضية إلى التحولية ، ولكن نأمل في المستقبل الافتراضي هو أكثر على immutablity (انظر قائمة أمنيات القادمة تعميم لغة البرمجة).

عامل واحد هو أنه إذا كانت السلاسل قابلة للتغيير ، الكائنات تخزين السلاسل يجب أن تكون حذرا لتخزين النسخ لئلا البيانات الداخلية للتغيير دون إشعار.بالنظر إلى أن السلاسل إلى حد ما نوع بدائي مثل الأرقام ، فمن الجميل عندما يمكن للمرء أن نعاملهم كما لو كانوا تمريرها حسب القيمة ، حتى لو كانت مرت الإشارة (الذي يساعد أيضا على حفظ في الذاكرة).

نجاح باهر!لا أصدق التضليل هنا.سلاسل كونها ثابتة لا يملكون شيئا مع الأمن.إذا كان شخص ما لديه بالفعل الوصول إلى الكائنات في تشغيل التطبيق (الذي يجب أن يكون من المفترض إذا كنت تحاول حماية ضد شخص 'القرصنة' سلسلة في التطبيق الخاص بك), بالتأكيد الكثير من الفرص الأخرى المتاحة القرصنة.

انها تماما فكرة الرواية التي ثبات سلسلة معالجة خيوط القضايا.هممم ...أنا كائن التي يتم تغييرها من قبل اثنين من المواضيع المختلفة.كيف يمكنني حل هذه المشكلة ؟ مزامنة الوصول إلى الكائن ؟ Naawww ...دعونا لا تدع أي شخص تغيير وجوه في كل شيء -- سيصلح كل فوضوي مشكلات التوافق!في الواقع, دعونا جعل كل الأشياء ثابتة ، ومن ثم يمكننا إزالة متزامنة contruct من لغة جافا.

السبب الحقيقي (أشار آخرون أعلاه) هو تحسين الذاكرة.فمن الشائع جدا في أي تطبيق لنفس سلسلة حرفية استخدامها مرارا وتكرارا.ومن الشائع جدا, في الواقع, أن عقود مضت, العديد من المجمعين جعلت الأمثل تخزين مثيل واحد فقط من سلسلة حرفية.عيب هذا الأمثل هو أن وقت التشغيل قانون بتعديل سلسلة حرفية يدخل المشكلة لأنه يتم تعديل سبيل المثال لجميع التعليمات البرمجية الأخرى التي أسهم ذلك.على سبيل المثال ، سيكون من غير جيدة للحصول على وظيفة في مكان ما في تطبيق لتغيير سلسلة حرفية "الكلب" إلى "القط".أ printf("الكلب") سيؤدي إلى "القط" من كتابة المعياري.ولهذا السبب هناك حاجة إلى أن يكون وسيلة حراسة ضد رمز محاولات لتغيير سلسلة حرفية (أنا.ه. ، جعلها غير قابلة للتغيير).بعض المجمعين (بدعم من نظام التشغيل) أن إنجاز هذا من خلال وضع سلسلة حرفية في ذاكرة للقراءة فقط الجزء الذي سوف يتسبب في الذاكرة خطأ إن الكتابة محاولة.

في جاوة هذا هو المعروف باسم التدريب.المحول البرمجي Java هنا هو مجرد عقب الذاكرة القياسية الأمثل قام به القائمون على مدى عقود.وأن تعالج نفس القضية هذه سلسلة حرفية يجري تعديلها في وقت التشغيل جافا ببساطة يجعل الطبقة سلسلة ثابتة (أنا.e, يعطيك المحددات التي من شأنها أن تسمح لك بتغيير محتوى سلسلة).سلاسل لا يجب أن تكون ثابتة إذا تتدرب من سلسلة حرفية لم يحدث.

سلسلة هو نوع بدائي ، ولكن عادة ما ترغب في استخدامه مع قيمة دلالات ، أيمثل قيمة.

قيمة هو شيء يمكنك أن تثق لن يغير من وراء ظهرك.إذا كنت أكتب: String str = someExpr(); أنت لا تريد أن تتغير إلا إذا كنت تفعل شيئا مع str.

سلسلة ككائن بطبيعة الحال المؤشر دلالات للحصول على قيمة دلالات كذلك فإنه يحتاج إلى أن تكون ثابتة.

أعرف أن هذا هو عثرة ، ولكن...هل هم حقا غير قابل للتغيير?النظر في المسائل التالية.

public static unsafe void MutableReplaceIndex(string s, char c, int i)
{
    fixed (char* ptr = s)
    {
        *((char*)(ptr + i)) = c;
    }
}

...

string s = "abc";
MutableReplaceIndex(s, '1', 0);
MutableReplaceIndex(s, '2', 1);
MutableReplaceIndex(s, '3', 2);
Console.WriteLine(s); // Prints 1 2 3

هل يمكن أن تجعل حتى طريقة تمديد.

public static class Extensions
{
    public static unsafe void MutableReplaceIndex(this string s, char c, int i)
    {
        fixed (char* ptr = s)
        {
            *((char*)(ptr + i)) = c;
        }
    }
}

مما يجعل العمل التالية

s.MutableReplaceIndex('1', 0);
s.MutableReplaceIndex('2', 1);
s.MutableReplaceIndex('3', 2);

الخلاصة:إنهم غير قابل للتغيير الدولة التي هو معروف من قبل المترجم.من تتسبب أعلاه ينطبق فقط على .صافي سلاسل جافا لا يجب المؤشرات.ومع ذلك سلسلة يمكن أن يكون كليا قابلة للتغيير باستخدام المؤشرات في C#.الأمر ليس كما مؤشرات تهدف إلى استخدامها ، وقد الاستخدام العملي أو بأمان ؛ ومع ذلك ممكن ، وبالتالي الانحناء كله "قابلة للتغيير" القاعدة.يمكنك عادة تعديل فهرس مباشرة من السلسلة و هذا هو السبيل الوحيد.هناك طريقة يمكن أن يمنع هذا عن طريق عدم السماح مؤشر حالات سلاسل أو صنع نسخة عند سلسلة وأشار إلى, ولكن لا يتم ذلك ، مما يجعل السلاسل في C# ليس تماما غير قابل للتغيير.

بالنسبة لمعظم الأغراض ، "السلسلة" هو (المستخدمة/تعامل/الفكر/يفترض أن يكون) معنى الذرية الوحدة ، تماما مثل عدد.

يسأل لماذا الفردية الأحرف من سلسلة غير قابلة للتغيير ولذلك كمن يسأل لماذا الفردية بت عدد صحيح غير قابلة للتغيير.

يجب أن نعرف لماذا.مجرد التفكير في ذلك.

أنا أكره أن أقول ذلك, ولكن للأسف نحن نتناقش في هذا لأن لغتنا سيء, نحن نحاول استخدام كلمة واحدة ، سلسلة, وصف معقدة السياق يقع مفهوم أو فئة الكائن.

نقوم بإجراء العمليات الحسابية والمقارنات مع "السلاسل" على غرار كيف نفعل مع الأرقام.إذا السلاسل (أو الأعداد الصحيحة) كانت قابلة للتغيير يجب كتابة رمز خاص لقفل قيم ثابتة الأشكال المحلية من أجل أداء أي نوع من حساب موثوق.ولذلك فمن الأفضل أن نفكر في مثل سلسلة معرف رقمي ، ولكن بدلا من 16 ، 32 أو 64 بت طويلة ، يمكن أن يكون مئات من البتات طويلة.

عندما يقول شخص ما "السلسلة" ، نحن جميعا نفكر في أشياء مختلفة.أولئك الذين يعتقدون أنه مجرد مجموعة من الشخصيات ، مع عدم وجود غرض معين في الاعتبار ، بالطبع سوف يكون روع شخص قررت فقط أنها ينبغي أن تكون قادرة على التعامل مع تلك الشخصيات.ولكن "السلسلة" فئة ليست مجرد مجموعة من الحروف.انها STRING, لا char[].هناك بعض الافتراضات الأساسية حول مفهوم نشير إلى أنها "السلسلة" ، و عموما فإنه يمكن وصفها بأنها ذات معنى الذرية وحدة ترميز البيانات مثل عدد.عندما يتحدث الناس عن "التلاعب في السلاسل" ، وربما أنهم حقا نتحدث عن التلاعب الشخصيات لبناء سلاسل, و بـ stringbuilder كبيرة من أجل ذلك.فقط فكر قليلا عن ما كلمة "السلسلة" حقا يعني.

تنظر في لحظة ما سيكون عليه إذا كانت السلاسل قابلة للتغيير.API التالية وظيفة يمكن أن يكون غرر العودة معلومات عن مستخدم آخر إذا قابلة للتغيير اسم السلسلة عن قصد أو عن غير قصد تعديلها من قبل مؤشر ترابط آخر في حين أن هذه هي وظيفة باستخدام الأمر:

string GetPersonalInfo( string username, string password )
{
    string stored_password = DBQuery.GetPasswordFor( username );
    if (password == stored_password)
    {
        //another thread modifies the mutable 'username' string
        return DBQuery.GetPersonalInfoFor( username );
    }
}

الأمن ليس فقط حول 'التحكم في الوصول ، بل أيضا حول سلامة" و "ضمان صحة'.إذا كان الأسلوب لا يمكن أن يكون بسهولة مكتوب ويعتمد على إجراء عملية حسابية بسيطة أو المقارنة موثوق, ثم انها ليست آمنة لكن سيكون من المأمون أن يشكك في لغة البرمجة نفسها.

ثبات ليس ارتباطا وثيقا الأمن.هذا على الأقل .NET, يمكنك الحصول على SecureString الدرجة.

إنها مقايضة.سلاسل تذهب إلى سلسلة تجمع عند إنشاء عدة سالسل متطابقة أنها تشترك في نفس الذاكرة.المصممين أحسب هذه الذاكرة توفير هذه التقنية تعمل بشكل جيد من أجل قضية مشتركة ، منذ البرامج تميل إلى طحن خلال نفس السلاسل الكثير.

الجانب السلبي هو أن تسلسالت جعل الكثير من خارج السلاسل التي الانتقالية فقط و فقط أصبحت القمامة ، في الواقع تضر أداء الذاكرة.لديك StringBuffer و بـ stringbuilder (في جاوة ، بـ stringbuilder أيضا .صافي) استخدام للحفاظ على الذاكرة في هذه الحالات.

قرار سلسلة قابلة للتغيير في C++ يسبب الكثير من المشاكل ، راجع هذا المقال الممتاز قبل كلفن Henney عن مرض جنون البقر.

البقر = نسخ على الكتابة.

سلاسل في جافا لا حقا غير قابل للتغيير ، يمكنك تغيير القيمة باستخدام التفكير أو فئة التحميل.يجب أن لا يكون اعتمادا على أن الملكية الأمن.للحصول على أمثلة انظر: خدعة سحرية في جافا

ثبات جيد.انظر فعالة جافا.إذا كان لديك نسخ سلسلة في كل مرة يمكنك تمرير حولها, ثم أن الكثير من عرضة للخطأ رمز.لديك أيضا التباس التعديلات التي تؤثر على المراجع.في بنفس الطريقة التي عدد صحيح يجب أن تكون ثابتة على التصرف مثل int, سلاسل يجب أن تتصرف كما قابل للتغيير أن تتصرف مثل الأوليات.في C++ يمر سلاسل من قيمة هذا لا دون ذكر صريح في التعليمات البرمجية المصدر.

هناك استثناء تقريبا تقريبا كل حكم:

using System;
using System.Runtime.InteropServices;

namespace Guess
{
    class Program
    {
        static void Main(string[] args)
        {
            const string str = "ABC";

            Console.WriteLine(str);
            Console.WriteLine(str.GetHashCode());

            var handle = GCHandle.Alloc(str, GCHandleType.Pinned);

            try
            {
                Marshal.WriteInt16(handle.AddrOfPinnedObject(), 4, 'Z');

                Console.WriteLine(str);
                Console.WriteLine(str.GetHashCode());
            }
            finally
            {
                handle.Free();
            }
        }
    }
}

إلى حد كبير لأسباب أمنية.انها اصعب بكثير من تأمين النظام إذا كان لا يمكنك أن تثق أن سلاسل تزويرها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top