Frage

Aktualisieren : Dies ist mehr oder weniger ein Betrogene , und es stellt sich heraus Compiler Magie, um einen Konstruktor Zugabe in build2 in den lokalen variablen zu übergeben.

eine Schnittstelle wie solche Gegeben:

public interface IFoo { public int get(); }

Der folgende Code druckt 1, 1, 2 und wirft dann eine Ausnahme, wenn sie versuchen getClass () aufrufen. NewInstance () auf dem Wert von build2 zurückgegeben, aber nicht, wenn sie auf dem Rückgabewert von build1 den gleichen Aufruf. Irgendwelche Ideen, warum?

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());
 }
}

Mein Debugger zeigt an, dass in der newInstance () -Aufruf, getConstructor0 eine NoSuchMethodException wirft.

War es hilfreich?

Lösung

Hier ist, was passiert:

  • newInstance() erfordert eine nullary Konstruktor
  • , wenn Sie eine anonyme Klasse erstellen, die eine final Variable zugreift, wird ein Feld tatsächlich implizit erstellt, diesen Wert zu halten, die sich zunächst auf den impliziten Konstruktor übergeben wird
  • damit die IFoo in build2 erstellt eigentlich nicht haben eine nullary Konstruktor

Hier ist ein Ausschnitt zu zeigen, was los ist:

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)
    }
}

Es zeigt, dass Foo$1 (die zugewiesene binären Namen für die anonyme IFoo Klasse) nur ein Konstruktor hat, und es dauert eine int. Dies ist, wie es return v kann, weil das, was zurückgegeben werden ist eigentlich, was auf die implizit erstellt von diesem implizit erstellt Konstruktor zugewiesen wird.

Es ist lehrreich, die Foo$1 zu dekompilieren (beispielsweise unter Verwendung javap -c), um zu sehen, was Bytecode erzeugt wird. Sie werden sehen, dass in der Tat das ist, was passiert, wenn ein final Variable von einer anonymen Klasse zugegriffen wird.

Verwandte Fragen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top