لماذا يجعل التشغيل التلقائي بعض المكالمات غامضة في Java؟

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

سؤال

لقد لاحظت اليوم أن الملاكمة التلقائية يمكن أن تسبب أحيانًا غموضًا في حل التحميل الزائد للطريقة.يبدو أن أبسط مثال هو:

public class Test {
    static void f(Object a, boolean b) {}
    static void f(Object a, Object b) {}

    static void m(int a, boolean b) { f(a,b); }
}

عندما يتم تجميعه، فإنه يسبب الخطأ التالي:

Test.java:5: reference to f is ambiguous, both method
    f(java.lang.Object,boolean) in Test and method
    f(java.lang.Object,java.lang.Object) in Test match

static void m(int a, boolean b) { f(a, b); }
                                  ^

إصلاح هذا الخطأ تافه:ما عليك سوى استخدام الملاكمة التلقائية الصريحة:

static void m(int a, boolean b) { f((Object)a, b); }

الذي يستدعي الحمل الزائد الأول بشكل صحيح كما هو متوقع.

فلماذا فشل حل التحميل الزائد؟لماذا لم يقوم المترجم بوضع الوسيطة الأولى تلقائيًا، وقبول الوسيطة الثانية بشكل طبيعي؟لماذا كان علي أن أطلب الملاكمة التلقائية بشكل صريح؟

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

المحلول

عند يلقي الوسيطة الأولى إلى كائن نفسك، فإن المترجم تتطابق مع طريقة دون استخدام autoboxing (JLS3 15.12.2):

<اقتباس فقرة>   

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

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

<اقتباس فقرة>   

وأما المرحلة الثانية (§15.12.2.3) ينفذ   قرار الزائد مع السماح   الملاكمة وعلبته، ولكن لا يزال   يمنع استخدام arity متغير   استدعاء الأسلوب.

لماذا، في المرحلة الثانية، لا المترجم اختيار الطريقة الثانية لأنه لا يوجد autoboxing من حجة منطقية ضروري؟ لأنه بعد ذلك وجدت الطرق مطابقة اثنين، ويستخدم فقط تحويل النوع الفرعي لتحديد الطريقة الأكثر تحديدا من اثنين، بغض النظر عن أي الملاكمة أو علبته التي جرت لمطابقتها في المقام الأول (§15.12.2.5).

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

public class Test {
    static void f(Object a, boolean b) {}
    static void f(int a, Object b) {}

    static void m(int a, boolean b) { f(a, b); } // ambiguous
}

وتذكر أن الخوارزمية لاختيار طريقة مطابقة (تجميع لمرة والخطوة 2) هو ثابت وصفها في JLS. مرة واحدة في المرحلة 2 لا يوجد autoboxing انتقائية أو علبته. فإن المترجم تحديد موقع <م> جميع الطرق التي يمكن الوصول إليها (سواء الأساليب في هذه الحالات) وقابلة للتطبيق (مرة أخرى طريقتين)، وفقط بعد ذلك يختار واحد الأكثر تحديدا دون النظر في الملاكمة / علبته، وهو غامضة هنا.

نصائح أخرى

والمترجم <م> لم لصناعة السيارات في المربع الوسيطة الأولى. وبمجرد أن تم القيام به، وأنها الوسيطة الثانية هذا الغموض، لأنه يمكن أن ينظر إليها على أنها إما منطقية أو كائن.

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

عندما تقول و(أ، ب)، فإن المترجم في حيرة من أمره بشأن الوظيفة التي يجب أن يشير إليها.

هذا بسبب أ هو كثافة العمليات, ولكن الحجة المتوقعة في F هو كائن.لذلك يقرر المترجم التحويل أ إلى كائن.المشكلة الآن هي أنه إذا أ يمكن تحويلها إلى كائن، لذلك يمكن أن يكون ب.

هذا يعني أن استدعاء الوظيفة يمكن أن يشير إلى أي من التعريفين.وهذا يجعل المكالمة غامضة.

عندما تقوم بالتحويل أ إلى كائن يدويًا، يبحث المترجم فقط عن أقرب تطابق ثم يشير إليه.

لماذا لم يحدد برنامج التحويل البرمجي الوظيفة التي يمكن الوصول إليها من خلال "القيام بأقل عدد ممكن من تحويلات الملاكمة/غير الملاكمة"؟

انظر الحالة التالية:

f(boolean a, Object b)
f(Object a , boolean b)

إذا اتصلنا مثل و (منطقي أ، منطقي ب), ، ما هي الوظيفة التي يجب أن تختارها؟انها غامضة أليس كذلك؟وبالمثل، سيصبح الأمر أكثر تعقيدًا عند وجود الكثير من الحجج.لذلك اختار المترجم أن يعطيك تحذيرًا بدلاً من ذلك.

نظرًا لعدم وجود طريقة لمعرفة أي من الوظائف التي كان المبرمج ينوي استدعاءها حقًا، فإن المترجم يعطي خطأ.

<اقتباس فقرة>   

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

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

HTTP: //java.sun. كوم / مستندات / كتب / JLS / third_edition / أتش تي أم أل / expressions.html # 20448

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

ومن الأفضل أن يكون المواصفات واضحة ومفهومة ليقول ما سيحدث من لجعل الناس تخمين.

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

في المرحلة الثانية [§15.12.2.3]، يحدد مترجم الأساليب المعمول بها طريقة تحويل الاحتجاج [§5.3]، الذي هو مزيج من autoboxing والتصنيف الفرعي. حجة كثافة العمليات يمكن تحويلها إلى عدد صحيح، وهو نوع فرعي من كائن، على حد سواء الزائدة. حجة منطقية لا يحتاج إلى تحويل للالزائد الأول، ويمكن تحويلها إلى منطقية، وهو نوع فرعي من كائن، للمرة الثانية. لذلك، كل من طرق قابلة للتطبيق في المرحلة الثانية.

ومنذ أكثر من طريقة للتطبيق، المترجم يجب تحديد وهو الأكثر تحديدا [§15.12.2.5]. فإنه يقارن أنواع المعلمة، وليس أنواع حجة، وأنه لا autobox لهم. وجوه ومنطقية أنواع لا علاقة لها، لذلك فهي تعتبر محددة على حد سواء. ولا الأسلوب هو أكثر تحديدا من جهة أخرى، وبالتالي فإن استدعاء الأسلوب غامضة.

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

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