Guide til Guavas refleksionsværktøjer

1. Oversigt

I denne artikel ser vi på Guavaafspejling API - som bestemt er mere alsidig sammenlignet med standard Java-refleksions-API.

Vi bruger Guava for at fange generiske typer ved kørsel, og vi gør god brug af det Påkaldelig såvel.

2. Optagelse af generisk type ved kørselstid

I Java implementeres generiske gener med typesletning. Det betyder, at informationen om generisk type kun er tilgængelig på kompileringstidspunktet, og at den ikke længere er tilgængelig under kørsel.

For eksempel, Liste, oplysningerne om generisk type slettes ved kørsel. På grund af den kendsgerning er det ikke sikkert at passere generisk Klasse objekter ved kørselstid.

Vi kan ende med at tildele to lister, der har forskellige generiske typer, til den samme reference, hvilket tydeligvis ikke er en god idé:

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

På grund af sletning af typen er metoden isAssignableFrom () kan ikke kende den faktiske generiske type af listerne. Det sammenligner grundlæggende to typer, der bare er en Liste uden oplysninger om den aktuelle type.

Ved at bruge standard Java-refleksions-API kan vi registrere de generiske typer metoder og klasser. Hvis vi har en metode, der returnerer en Liste, kan vi bruge refleksion til at opnå returtypen for denne metode - a ParameterizedType repræsenterer Liste.

Det TypeToken klasse bruger denne løsning til at tillade manipulation af generiske typer. Vi kan bruge TypeToken klasse for at fange en faktisk type generisk liste og kontrollere, om de virkelig kan henvises til med den samme reference:

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

Kun den integerListToken kan tildeles en type reference nubmerTypeToken fordi en Heltal klasse udvider en Nummer klasse.

3. Optagelse af komplekse typer ved hjælp af TypeToken

Lad os sige, at vi vil oprette en generisk parametreret klasse, og vi vil have oplysninger om en generisk type ved kørsel. Vi kan oprette en klasse, der har en TypeToken som et felt til at fange disse oplysninger:

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

Derefter, når du opretter en forekomst af denne klasse, vil den generiske type være tilgængelig under kørsel:

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

Vi kan også oprette en TypeToken af en kompleks type, der har mere end en generisk type, og henter oplysninger om hver af disse typer ved kørselstid:

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

Vi får en faktisk returretype for Fungere, det er en Snor. Vi kan endda få en type post på kortet:

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

Her bruger vi en refleksionsmetode getMethod () fra Java-standardbiblioteket for at registrere returtypen for en metode.

4. Påkaldelig

Det Påkaldelig er en flydende indpakning af java.lang.reflect.Methode og java.lang.reflect.Constructor. Det giver en enklere API oven på en standard Java afspejling API. Lad os sige, at vi har en klasse, der har to offentlige metoder, og en af ​​dem er endelig:

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

Lad os nu undersøge somePublicMethod () ved hjælp af Guava API og Java-standard afspejling API:

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

Der er ikke meget forskel mellem disse to varianter, men det er en virkelig ikke-triviel opgave i Java at kontrollere, om en metode er overstyrbar. Heldigvis er isOverridable () metode fra Påkaldelig klasse gør det lettere:

Metodemetode = CustomClass.class.getMethod ("notOverridablePublicMethod"); Invokable invokable = new TypeToken () {} .method (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ådan simpel operation kræver en masse kontrol ved hjælp af standard afspejling API. Det Påkaldelig klasse skjuler dette bag API'en, der er enkel at bruge og meget kortfattet.

5. Konklusion

I denne artikel kiggede vi på Guava refleksions API og sammenlignede det med standard Java. Vi så, hvordan man opfanger generiske typer ved kørsel, og hvordan Påkaldelig klasse giver elegant og brugervenlig API til kode, der bruger refleksion.

Implementeringen af ​​alle disse eksempler og kodestykker findes i GitHub-projektet - dette er et Maven-projekt, så det skal være let at importere og køre, som det er.


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