Gids voor Guava’s Reflection Utilities

1. Overzicht

In dit artikel zullen we kijken naar de Guavereflectie API - die zeker veelzijdiger is in vergelijking met de standaard Java-reflectie-API.

We zullen gebruiken Guave om generieke typen tijdens runtime vast te leggen, en we zullen er goed gebruik van maken Aanroepbaar ook.

2. Generic Type vastleggen tijdens Runtime

In Java worden generieke geneesmiddelen geïmplementeerd met het wissen van typen. Dat betekent dat de algemene type-informatie alleen beschikbaar is tijdens het compileren en tijdens runtime niet langer beschikbaar is.

Bijvoorbeeld, Lijst, de informatie over het generieke type wordt tijdens runtime gewist. Vanwege dat feit is het niet veilig om generiek door te geven Klasse objecten tijdens runtime.

We zouden uiteindelijk twee lijsten met verschillende generieke typen aan dezelfde referentie kunnen toewijzen, wat duidelijk geen goed idee is:

Lijst stringList = Lists.newArrayList (); List intList = Lists.newArrayList (); booleaans resultaat = stringList.getClass () .isAssignableFrom (intList.getClass ()); assertTrue (resultaat);

Vanwege het wissen van het type, is de methode isAssignableFrom () kan het werkelijke generieke type van de lijsten niet kennen. Het vergelijkt in feite twee typen die slechts een Lijst zonder enige informatie over het werkelijke type.

Door de standaard Java-reflectie-API te gebruiken, kunnen we de generieke soorten methoden en klassen detecteren. Als we een methode hebben die een Lijstkunnen we reflectie gebruiken om het retourtype van die methode te verkrijgen - a ParameterizedType vertegenwoordigen Lijst.

De TypeToken class gebruikt deze tijdelijke oplossing om de manipulatie van generieke typen toe te staan. We kunnen de TypeToken class om een ​​actueel type generieke lijst vast te leggen en te controleren of er echt naar kan worden verwezen door dezelfde referentie:

TypeToken stringListToken = nieuw TypeToken() {}; TypeToken integerListToken = nieuw TypeToken() {}; TypeToken numberTypeToken = nieuw TypeToken() {}; assertFalse (stringListToken.isSubtypeOf (integerListToken)); assertFalse (numberTypeToken.isSubtypeOf (integerListToken)); assertTrue (integerListToken.isSubtypeOf (numberTypeToken));

Alleen de integerListToken kan worden toegewezen aan een referentie van het type nubmerTypeToken omdat een Geheel getal klasse breidt een Aantal klasse.

3. Complexe typen vastleggen met TypeToken

Laten we zeggen dat we een generieke klasse met parameters willen maken en dat we tijdens runtime informatie willen hebben over een generiek type. We kunnen een klasse maken met een TypeToken als een veld om die informatie vast te leggen:

abstracte klasse ParametrizedClass {TypeToken type = nieuw TypeToken (getClass ()) {}; }

Wanneer u vervolgens een instantie van die klasse maakt, is het generieke type beschikbaar tijdens runtime:

ParametrizedClass parametrizedClass = new ParametrizedClass () {}; assertEquals (parametrizedClass.type, TypeToken.of (String.class));

We kunnen ook een TypeToken van een complex type dat meer dan één generiek type heeft, en informatie over elk van die typen tijdens runtime ophalen:

TypeToken funToken = nieuw TypeToken() {}; TypeToken funResultToken = funToken .resolveType (Function.class.getTypeParameters () [1]); assertEquals (funResultToken, TypeToken.of (String.class));

We krijgen een actueel retourtype voor Functie, dat is een Draad. We kunnen zelfs een type van het item op de kaart krijgen:

TypeToken mapToken = nieuw TypeToken() {}; TypeToken entrySetToken = mapToken .resolveType (Map.class.getMethod ("entrySet") .getGenericReturnType ()); assertEquals (entrySetToken, nieuw TypeToken<>>() {}); 

Hier gebruiken we een reflectiemethode getMethod () van de Java-standaardbibliotheek om het retourtype van een methode vast te leggen.

4. Aanroepbaar

De Aanroepbaar is een vloeiende verpakking van java.lang.reflect.Method en java.lang.reflect.Constructor. Het biedt een eenvoudigere API bovenop een standaard Java reflectie API. Laten we zeggen dat we een klasse hebben met twee openbare methoden en een daarvan is definitief:

class CustomClass {public void somePublicMethod () {} public final void notOverridablePublicMethod () {}}

Laten we nu eens kijken naar het somePublicMethod () met behulp van Guava API en Java-standaard reflectie API:

Method method = CustomClass.class.getMethod ("somePublicMethod"); Invokable invokable = new TypeToken () {} .method (methode); boolean isPublicStandradJava = Modifier.isPublic (method.getModifiers ()); boolean isPublicGuava = invokable.isPublic (); assertTrue (isPublicStandradJava); assertTrue (isPublicGuava);

Er is niet veel verschil tussen deze twee varianten, maar het controleren of een methode overschrijfbaar is, is een niet-triviale taak in Java. Gelukkig is de isOverridable () methode van de Aanroepbaar klasse maakt het gemakkelijker:

Method method = CustomClass.class.getMethod ("notOverridablePublicMethod"); Invokable invokable = new TypeToken () {} .method (methode); 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);

We zien dat zelfs zo'n eenvoudige operatie veel controles met behulp van standaard vereist reflectie API. De Aanroepbaar class verbergt dit achter de API die eenvoudig te gebruiken en zeer beknopt is.

5. Conclusie

In dit artikel keken we naar de Guava-reflectie-API en vergeleken we deze met de standaard Java. We hebben gezien hoe generieke typen tijdens runtime kunnen worden vastgelegd en hoe de Aanroepbaar class biedt een elegante en gebruiksvriendelijke API voor code die reflectie gebruikt.

De implementatie van al deze voorbeelden en codefragmenten is te vinden in het GitHub-project - dit is een Maven-project, dus het moet gemakkelijk te importeren en uit te voeren zijn zoals het is.