Guide til Guava's Reflection Utilities

1. Oversikt

I denne artikkelen ser vi på Guavaspeilbilde API - som definitivt er mer allsidig sammenlignet med standard Java refleksjon API.

Vi bruker Guava for å fange generiske typer ved kjøretid, og vi vil gjøre god bruk av det Påkallelig også.

2. Fange generisk type ved kjøretid

I Java implementeres generikk med typesletting. Det betyr at informasjonen om generisk type bare er tilgjengelig på kompileringstidspunktet, og at den ikke lenger er tilgjengelig på kjøretid.

For eksempel, Liste, informasjonen om generisk type blir slettet ved kjøretid. På grunn av det faktum er det ikke trygt å passere generisk Klasse objekter ved kjøretid.

Vi kan ende opp med å tildele to lister som har forskjellige generiske typer til samme referanse, noe som tydeligvis ikke er en god ide:

List stringList = Lists.newArrayList (); List intList = Lists.newArrayList (); boolsk resultat = stringList.getClass () .isAssignableFrom (intList.getClass ()); assertTrue (resultat);

På grunn av type sletting, metoden isAssignableFrom () kan ikke vite den generelle typen av listene. Det sammenligner i utgangspunktet to typer som bare er en Liste uten informasjon om den faktiske typen.

Ved å bruke standard Java refleksjon API kan vi oppdage generiske typer metoder og klasser. Hvis vi har en metode som returnerer en Liste, kan vi bruke refleksjon for å oppnå returtypen for den metoden - a ParameterizedType representerer Liste.

De TypeToken klasse bruker denne løsningen for å tillate manipulering av generiske typer. Vi kan bruke TypeToken klasse for å fange en faktisk type generisk liste og sjekke om de virkelig kan refereres til med samme referanse:

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

Bare den integerListToken kan tilordnes en referanse av typen nubmerTypeToken fordi en Heltall klasse utvider a Nummer klasse.

3. Fange komplekse typer ved hjelp av TypeToken

La oss si at vi vil lage en generisk parameterisert klasse, og vi vil ha informasjon om en generisk type ved kjøretid. Vi kan lage en klasse som har en TypeToken som et felt for å fange den informasjonen:

abstrakt klasse ParametrizedClass {TypeToken type = ny TypeToken (getClass ()) {}; }

Deretter, når du oppretter en forekomst av den klassen, vil den generiske typen være tilgjengelig ved kjøretid:

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

Vi kan også lage en TypeToken av en kompleks type som har mer enn en generisk type, og henter informasjon om hver av disse typene ved kjøretid:

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

Vi får en faktisk returtype for Funksjon, det er en String. Vi kan til og med få en type oppføring på kartet:

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

Her bruker vi en refleksjonsmetode getMethod () fra Java standardbibliotek for å fange returtypen til en metode.

4. Påkallelig

De Påkallelig er en flytende innpakning av java.lang.reflect.Methode og java.lang.reflect.Constructor. Det gir en enklere API på toppen av en standard Java speilbilde API. La oss si at vi har en klasse som har to offentlige metoder, og en av dem er endelig:

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

La oss nå undersøke somePublicMethod () bruker Guava API og Java-standard speilbilde API:

Metodemetode = CustomClass.class.getMethod ("somePublicMethod"); Invokable invokable = new TypeToken () {} .metode (metode); boolsk isPublicStandradJava = Modifier.isPublic (method.getModifiers ()); boolsk isPublicGuava = invokable.isPublic (); assertTrue (isPublicStandradJava); assertTrue (isPublicGuava);

Det er ikke mye forskjell mellom disse to variantene, men å sjekke om en metode er overstyrbar er en veldig ikke-triviell oppgave i Java. Heldigvis, den isOverridable () metoden fra Påkallelig klasse gjør det lettere:

Metodemetode = CustomClass.class.getMethod ("notOverridablePublicMethod"); Invokable invokable = new TypeToken () {} .metode (metode); boolean isOverridableStandardJava = (! (Modifier.isFinal (method.getModifiers ()) || Modifier.isPrivate (method.getModifiers ()) || Modifier.isStatic (method.getModifiers ()) || Modifier.isFinal (method.getDeclaringClass ( ) .getModifiers ()))); boolsk isOverridableFinalGauava = invokable.isOverridable (); assertFalse (isOverridableStandardJava); assertFalse (erOverridableFinalGauava);

Vi ser at selv en så enkel operasjon trenger mange kontroller ved hjelp av standard speilbilde API. De Påkallelig klasse gjemmer dette bak API som er enkel å bruke og veldig kortfattet.

5. Konklusjon

I denne artikkelen så vi på Guava refleksjon API og sammenlignet den med standard Java. Vi så hvordan å fange generiske typer ved kjøretid, og hvordan Påkallelig klasse gir elegant og brukervennlig API for kode som bruker refleksjon.

Implementeringen av alle disse eksemplene og kodebitene finnes i GitHub-prosjektet - dette er et Maven-prosjekt, så det skal være enkelt å importere og kjøre som det er.


$config[zx-auto] not found$config[zx-overlay] not found