Super Type Tokens i Java Generics

1. Oversikt

I denne opplæringen skal vi bli kjent med topper av supertype og se hvordan de kan hjelpe oss med å bevare generisk typeinformasjon ved kjøretid.

2. Slettingen

Noen ganger trenger vi å formidle bestemt type informasjon til en metode. For eksempel forventer vi her fra Jackson å konvertere JSON-byte-matrisen til en Streng:

byte [] data = // hent json fra et sted String json = objectMapper.readValue (data, String.class);

Vi kommuniserer denne forventningen via et bokstavelig klassetoken, i dette tilfellet Strengklasse.

Vi kan imidlertid ikke stille den samme forventningen for generiske typer så enkelt:

Kart json = objectMapper.readValue (data, Map.class); // vil ikke kompilere

Java sletter generisk typeinformasjon under kompilering. Derfor, generiske typeparametere er bare en gjenstand for kildekoden og vil være fraværende ved kjøretid.

2.1. Reifisering

Teknisk sett blir generiske typer ikke reified i Java. I programmeringsspråkets terminologi, når en type er til stede ved kjøretid, sier vi at typen blir reified.

De reified typene i Java er som følger:

  • Enkle primitive typer som lang
  • Ikke-generiske abstraksjoner som String eller Kjørbar
  • Rå typer som Liste eller HashMap
  • Generiske typer der alle typer er ubegrensede jokertegn som Liste eller HashMap
  • Arrays av andre reified typer som Streng [], int [], Liste [], eller Kart[]

Derfor kan vi ikke bruke noe sånt Map.class fordi det Kart er ikke en reified type.

3. Super Type Token

Som det viser seg, kan vi dra nytte av kraften til anonyme indre klasser i Java for å bevare typeinformasjonen under kompileringstiden:

offentlig abstrakt klasse TypeReference {privat slutt Type type; public TypeReference () {Type superclass = getClass (). getGenericSuperclass (); type = ((ParameterizedType) superklasse) .getActualTypeArguments () [0]; } offentlig Type getType () {returtype; }}

Denne klassen er abstrakt, så vi kan bare utlede underklasser fra den.

For eksempel kan vi lage en anonym indre:

Type Referanse token = ny TypeReference() {};

Konstruktøren gjør følgende for å bevare typeinformasjonen:

  • For det første får den generiske superklass-metadata for denne spesielle forekomsten - i dette tilfellet er den generiske superklassen Type Referanse
  • Deretter får den og lagrer den faktiske typeparameteren for den generiske superklassen - i dette tilfellet ville det være Kart

Denne tilnærmingen for å bevare den generiske typen informasjon er vanligvis kjent som super type token:

Type Referanse token = ny TypeReference() {}; Type type = token.getType (); assertEquals ("java.util.Map", type.getTypeName ()); Type [] typeArguments = (((ParameterizedType) type) .getActualTypeArguments (); assertEquals ("java.lang.String", typeArguments [0] .getTypeName ()); assertEquals ("java.lang.Integer", typeArguments [1] .getTypeName ());

Ved hjelp av topper av supertype vet vi at containertypen er Kart, og også, dens type parametere er String og Heltall.

Dette mønsteret er så kjent at biblioteker som Jackson og rammer som Spring har sine egne implementeringer av det. Analyse av et JSON-objekt i en Kart kan oppnås ved å definere den typen med et supertypetoken:

Type Referanse token = ny TypeReference() {}; Kart json = objectMapper.readValue (data, token);

4. Konklusjon

I denne opplæringen lærte vi hvordan vi kan bruke supertype-tokens for å bevare den generiske typen informasjon under kjøretid.

Som vanlig er alle eksemplene tilgjengelige på GitHub.


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