لماذا لا يستطيع مترجم/JVM فقط جعل autoboxing "فقط العمل" ؟
-
25-09-2019 - |
سؤال
Autoboxing هو مخيفة إلى حد ما.بينما أنا أفهم تماما الفرق بين ==
و .equals
لا أستطيع إلا أن تساعد لديك اتبع علة الجحيم لي:
final List<Integer> foo = Arrays.asList(1, 1000);
final List<Integer> bar = Arrays.asList(1, 1000);
System.out.println(foo.get(0) == bar.get(0));
System.out.println(foo.get(1) == bar.get(1));
أن يطبع
true
false
لماذا لم تفعل ذلك بهذه الطريقة ؟ ذلك أن تفعل شيئا مع مؤقتا الاعداد الصحيحه ، ولكن إذا كان هذا هو الحال لماذا لا مجرد ذاكرة التخزين المؤقت جميع الأعداد المستخدمة من قبل البرنامج ؟ أو لماذا لا JVM دائما السيارات خدمة unbox إلى بدائية ؟
الطباعة false false أو true صحيحا لكان أفضل.
تحرير
أنا أختلف عن الكسر من القانون القديم.من خلال وجود foo.get(0) == bar.get(0)
العودة الحقيقية لقد كسرت الشفرة.
لا يمكن أن يكون هذا حل في المترجم المستوى من خلال استبدال عدد صحيح مع الباحث في رمز بايت (طالما أنها لم يكلف null)
المحلول
- لماذا فعلوا ذلك بهذه الطريقة؟
يتم تخزين كل عدد صحيح بين -128 و 127 بواسطة Java. لقد فعلوا هذا ، من المفترض ، لفائدة الأداء. حتى لو أرادوا العودة إلى هذا القرار الآن ، فمن غير المرجح أن يفعلوا ذلك. إذا قام أي شخص ببناء رمز اعتمادًا على هذا ، فسوف ينهار رمزه عند إخراجه. بالنسبة لترميز الهوايات ، ربما لا يهم هذا ، ولكن بالنسبة لقانون المؤسسة ، ينزعج الناس وتحدث الدعاوى القضائية.
- لماذا لا يقومون فقط بتخزين جميع الأعداد الصحيحة التي يستخدمها البرنامج؟
لا يمكن تخزين جميع الأعداد الصحيحة مؤقتًا ، لأن الآثار المترتبة على الذاكرة ستكون هائلة.
- لماذا لا JVM دائما unbox إلى بدائية؟
لأن JVM لا يمكن أن تعرف ما تريد. أيضا ، يمكن أن يكسر هذا التغيير بسهولة الكود القديم غير مصمم للتعامل مع هذه الحالة.
إذا كان JVM لإلغاء اللاصطدام تلقائيًا على البدائل على المكالمات إلى == ، فستصبح هذه المشكلة في الواقع أكثر إرباكًا. تحتاج الآن إلى أن تتذكر أن == يقارن دائمًا مراجع الكائنات ، ما لم يكن الكائنات غير مرغوب فيها. هذا من شأنه أن يتسبب في حالات مربكة أكثر غرابة تمامًا مثل تلك التي ذكرتها أعلاه.
بدلاً من ذلك ، قلقًا جدًا بشأن هذا ، فقط تذكر هذه القاعدة بدلاً من ذلك:
مطلقا قارن الكائنات بـ == إلا إذا كنت تنوي مقارنتها من خلال مراجعها. إذا قمت بذلك ، فلا يمكنني التفكير في سيناريو تصادف فيه مشكلة.
نصائح أخرى
هل يمكنك أن تتخيل مدى سوء الأداء إذا كان كل شيء Integer
تحمل النفقات العامة للاعتقال؟ أيضا لا يعمل ل new Integer
.
لا يمكن دائمًا أن تكون لغة Java (وليس مشكلة JVM) تلقائيًا لأن الكود المصمم لـ Java قبل 1.5 يجب أن يعمل.
Integer
s في نطاق البايت هي نفس الكائن ، لأنهم مؤقتا. Integer
s خارج نطاق البايت لا.إن جميع الأعداد الصحيحة أن يكون مؤقتا ، تخيل الذاكرة المطلوبة.
و من هنا
النتيجة من كل هذا السحر هو أنه يمكنك أن تتجاهل إلى حد كبير التمييز بين الباحث و صحيح ، مع بعض المحاذير.صحيح التعبير يمكن أن يكون لها قيمة فارغة.إذا كان البرنامج يحاول autounbox null, فإنه سيتم رمي NullPointerException.عامل التشغيل == ينفذ مرجعية الهوية مقارنات على عدد صحيح تعابير قيمة المساواة مقارنات على الباحث التعبيرات.وأخيرا ، هناك أداء التكاليف المرتبطة الملاكمة و علبته ، حتى لو كان ذلك تلقائيا
إذا تخطيت Autoboxing تمامًا ، فلا يزال لديك هذا السلوك.
final List<Integer> foo =
Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));
final List<Integer> bar =
Arrays.asList(Integer.valueOf( 1 ), Integer.valueOf( 1000 ));
System.out.println(foo.get(0) == bar.get(0)); // true
System.out.println(foo.get(1) == bar.get(1)); // false
كن أكثر وضوحًا إذا كنت تريد سلوكًا محددًا:
final List<Integer> foo =
Arrays.asList( new Integer( 1 ), new Integer( 1000 ));
final List<Integer> bar =
Arrays.asList( new Integer( 1 ), new Integer( 1000 ));
System.out.println(foo.get(0) == bar.get(0)); // false
System.out.println(foo.get(1) == bar.get(1)); // false
هذا هو السبب ، لماذا يمتلك Eclipse Autoboxing كتحذير افتراضيًا.
يعاني الكثير من الناس من مشاكل في هذه القضية ، حتى الأشخاص الذين يكتبون كتبًا عن جافا.
في برمجة جافا المحترفين, فقط بوصات أدناه كانت الكاتب يتحدث عن المشكلات المتعلقة باستخدام الأعداد الصحيحة ذات الصناديق التلقائية كمفتاح في الهوية HashMap ، ويستخدم مفاتيح عدد صحيح من الصناديق في نقطة الضعيفة. القيم المثال التي يستخدمها أكبر من 128 ، لذلك تنجح مكالمة مجموعة القمامة الخاصة به. إذا كان شخص ما يستخدم مثاله واستخدام القيم الأصغر من 128 ، فإن مثاله سيفشل (بسبب المفتاح الذي يتم حصوله على Perma).
عندما تكتب
foo.get(0)
المترجم لا يهم كيفية إنشاء القائمة. ينظر فقط إلى نوع وقت الترجمة من القائمة FOO. لذلك ، إذا كانت هذه قائمةu003CInteger> ، سوف يعامل ذلك كقائمةu003CInteger> ، كما من المفترض أن تفعل ، وقائمةu003CInteger> الحصول على () دائما يعيد عدد صحيح. إذا كنت تريد استخدام == ، فعليك الكتابة
System.out.println(foo.get(0).intValue() == bar.get(0).intValue());
ليس
System.out.println(foo.get(0) == bar.get(0));
لأن هذا له معنى مختلف تماما.