Leitfaden zu den Reflexionshilfsprogrammen von Guava

Anleitung zu den Reflection Utilities von Guava

1. Überblick

In diesem Artikel befassen wir uns mit derGuavareflection-API, die im Vergleich zur Standard-Java-Reflection-API definitiv vielseitiger ist.

Wir werdenGuava verwenden, um generische Typen zur Laufzeit zu erfassen, und wir werden auchInvokable gut nutzen.

2. Generischen Typ zur Laufzeit erfassen

In Java, generics are implemented with type erasure. Das bedeutet, dass die generischen Typinformationen nur zur Kompilierungszeit verfügbar sind und zur Laufzeit nicht mehr verfügbar sind.

Beispiel:List<String>, Die Informationen zum generischen Typ erhaltenerased at runtime. Aus diesem Grund ist es nicht sicher, generischeClass-Objekte zur Laufzeit weiterzugeben.

Möglicherweise werden zwei Listen mit unterschiedlichen generischen Typen derselben Referenz zugewiesen, was eindeutig keine gute Idee ist:

List stringList = Lists.newArrayList();
List intList = Lists.newArrayList();

boolean result = stringList.getClass()
  .isAssignableFrom(intList.getClass());

assertTrue(result);

Aufgrund des Löschens des Typs kann die MethodeisAssignableFrom() den tatsächlichen generischen Typ der Listen nicht kennen. Grundsätzlich werden zwei Typen verglichen, die nurList sind und keine Informationen über den tatsächlichen Typ enthalten.

Mit der Standard-Java-Reflection-API können wir die generischen Arten von Methoden und Klassen erkennen. Wenn wir eine Methode haben, dieList<String> zurückgibt, können wir Reflexion verwenden, um den Rückgabetyp dieser Methode zu erhalten - aParameterizedType, derList<String> darstellt.

Die KlasseTypeTokenverwendet diese Problemumgehung, um die Manipulation generischer Typen zu ermöglichen. Wir können die KlasseTypeTokenverwenden, um einen tatsächlichen Typ einer generischen Liste zu erfassen und zu überprüfen, ob sie wirklich durch dieselbe Referenz referenziert werden können:

TypeToken> stringListToken
  = new TypeToken>() {};
TypeToken> integerListToken
  = new TypeToken>() {};
TypeToken> numberTypeToken
  = new TypeToken>() {};

assertFalse(stringListToken.isSubtypeOf(integerListToken));
assertFalse(numberTypeToken.isSubtypeOf(integerListToken));
assertTrue(integerListToken.isSubtypeOf(numberTypeToken));

Nur dieintegerListToken können einer Referenz vom TypnubmerTypeToken zugewiesen werden, da eineInteger-Klasse eineNumber-Klasse. erweitert

3. Erfassen komplexer Typen mitTypeToken

Angenommen, wir möchten eine generische parametrisierte Klasse erstellen und zur Laufzeit Informationen über einen generischen Typ erhalten. Wir können eine Klasse mit einemTypeToken als Feld erstellen, um diese Informationen zu erfassen:

abstract class ParametrizedClass {
    TypeToken type = new TypeToken(getClass()) {};
}

Wenn Sie dann eine Instanz dieser Klasse erstellen, ist der generische Typ zur Laufzeit verfügbar:

ParametrizedClass parametrizedClass = new ParametrizedClass() {};

assertEquals(parametrizedClass.type, TypeToken.of(String.class));

Wir können auchTypeToken eines komplexen Typs mit mehr als einem generischen Typ erstellen und zur Laufzeit Informationen zu jedem dieser Typen abrufen:

TypeToken> funToken
  = new TypeToken>() {};

TypeToken funResultToken = funToken
  .resolveType(Function.class.getTypeParameters()[1]);

assertEquals(funResultToken, TypeToken.of(String.class));

Wir erhalten einen tatsächlichen Rückgabetyp fürFunction, dhString.. Wir können sogar einen Typ des Eintrags in der Karte erhalten:

TypeToken> mapToken
  = new TypeToken>() {};

TypeToken entrySetToken = mapToken
  .resolveType(Map.class.getMethod("entrySet")
  .getGenericReturnType());

assertEquals(
  entrySetToken,
  new TypeToken>>() {});

Hier verwenden wir eine ReflektionsmethodegetMethod() aus der Java-Standardbibliothek, um den Rückgabetyp einer Methode zu erfassen.

4. Invokable

Invokable ist eine fließende Hülle ausjava.lang.reflect.Method undjava.lang.reflect.Constructor. Es bietet eine einfachere API zusätzlich zu einer Standard-Javareflection-API. Nehmen wir an, wir haben eine Klasse mit zwei öffentlichen Methoden, von denen eine endgültig ist:

class CustomClass {
    public void somePublicMethod() {}

    public final void notOverridablePublicMethod() {}
}

Untersuchen wir nun diesomePublicMethod() mithilfe der Guava-API und der Java-Standardreflection-API:

Method method = CustomClass.class.getMethod("somePublicMethod");
Invokable invokable
  = new TypeToken() {}
  .method(method);

boolean isPublicStandradJava = Modifier.isPublic(method.getModifiers());
boolean isPublicGuava = invokable.isPublic();

assertTrue(isPublicStandradJava);
assertTrue(isPublicGuava);

Es gibt keinen großen Unterschied zwischen diesen beiden Varianten, aber die Überprüfung, ob eine Methode überschreibbar ist, ist in Java eine wirklich nicht triviale Aufgabe. Glücklicherweise macht es dieisOverridable()-Methode aus derInvokable-Klasse einfacher:

Method method = CustomClass.class.getMethod("notOverridablePublicMethod");
Invokable invokable
 = new TypeToken() {}.method(method);

boolean isOverridableStandardJava = (!(Modifier.isFinal(method.getModifiers())
  || Modifier.isPrivate(method.getModifiers())
  || Modifier.isStatic(method.getModifiers())
  || Modifier.isFinal(method.getDeclaringClass().getModifiers())));
boolean isOverridableFinalGauava = invokable.isOverridable();

assertFalse(isOverridableStandardJava);
assertFalse(isOverridableFinalGauava);

Wir sehen, dass selbst eine so einfache Operation viele Überprüfungen unter Verwendung der Standard-APIreflectionerfordert. Die KlasseInvokableverbirgt dies hinter der API, die einfach zu verwenden und sehr präzise ist.

5. Fazit

In diesem Artikel haben wir uns die Guava-Reflection-API angesehen und mit dem Standard-Java verglichen. Wir haben gesehen, wie generische Typen zur Laufzeit erfasst werden und wie die KlasseInvokableeine elegante und benutzerfreundliche API für Code bietet, der Reflektion verwendet.

Die Implementierung all dieser Beispiele und Codefragmente finden Sie inGitHub project - dies ist ein Maven-Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.