سؤال

تحديث: هذا أكثر أو أقل أ مغفل, ، واتضح أن يكون سحر المترجم يضيف مُنشئًا لتمريره في المتغير المحلي في Build2.

إعطاء واجهة مثل هذه:

public interface IFoo { public int get(); }

يطبع الكود أدناه 1 و 1 و 2 ثم يلقي استثناء عند محاولة الاتصال getClass (). newInstance () على القيمة التي تم إرجاعها بواسطة Build2 ، ولكن لا عند الاتصال بنفسها على القيمة التي تم إرجاعها من Build1. أي أفكار لماذا؟

public class Foo {

 public static IFoo build1() {
  return new IFoo() { public int get() { return 1; } };
 }

 public static IFoo build2(final int v) {
  return new IFoo() { public int get() {return v;} };
 }

 public static void main(String[] args) throws Exception {
  IFoo foo, bar;

  foo = build1();
  System.out.println(foo.get());

  bar = foo.getClass().newInstance();  
  System.out.println(bar.get());

  foo = build2(2);
  System.out.println(foo.get());

  bar = foo.getClass().newInstance();  
  System.out.println(bar.get());
 }
}

يشير مصحح الأخطاء الخاص بي إلى أنه في مكالمة NewInstance () ، يقوم GetConstructor0 بإلقاء NosuchmethodException.

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

المحلول

هذا ما يحدث:

  • newInstance() يتطلب مُنشئًا لاغية
  • عندما تقوم بإنشاء فئة مجهولة المصدر تصل إلى ملف final متغير ، يتم إنشاء حقل ضمنيًا في الواقع للاحتفاظ بهذه القيمة ، والذي يتم تمريره في البداية إلى مُنشئه الضمني
  • وهكذا ، و IFoo أنشئت في build2 ليس لديه في الواقع مُنشئ لا لبس

إليك مقتطف لإظهار ما يحدث:

import java.lang.reflect.*;
public class Foo {
    interface IFoo { public int get(); }

    public static IFoo build2(final int v) {
        return new IFoo() { public int get() {return v;} };
    }
    public static void main(String[] args) throws Exception {
        Class<?> klazz = build2(42).getClass();
        for (Constructor<?> c : klazz.getDeclaredConstructors()) {
            System.out.println(c);
        }
        // prints: Foo$1(int)
    }
}

إنها تظهر أن Foo$1 (الاسم الثنائي المعين للمجهول IFoo الطبقة) يحتوي على مُنشئ واحد فقط ، ويستغرق int. هكذا يمكن return v, ، لأن ما تم إرجاعه هو في الواقع كل ما يتم تعيينه إلى الحقل الذي تم إنشاؤه ضمنيًا بواسطة هذا المنشئ الذي تم إنشاؤه ضمنيًا.

من المفيد إلغاء تجميع Foo$1 (باستخدام مثل javap -c) لمعرفة ما يتم إنشاء رمز bytecode. سترى ذلك في الحقيقة هذا ما يحدث عندما أ final يتم الوصول إلى المتغير بواسطة فئة مجهولة.

أسئلة ذات صلة

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