Super Type Tokens i Java Generics

1. Oversigt

I denne vejledning bliver vi fortrolige med supertype-tokens og ser, hvordan de kan hjælpe os med at bevare generisk typeinformation under kørsel.

2. Sletningen

Nogle gange er vi nødt til at formidle bestemt typeinformation til en metode. For eksempel forventer vi her fra Jackson at konvertere JSON-byte-arrayet til en Snor:

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

Vi kommunikerer denne forventning via et bogstaveligt klassetoken, i dette tilfælde String.klasse.

Vi kan dog ikke indstille den samme forventning til generiske typer så let:

Kort json = objectMapper.readValue (data, Map.class); // kompilerer ikke

Java sletter generisk typeinformation under kompilering. Derfor, generiske typeparametre er kun en artefakt af kildekoden og vil være fraværende ved kørsel.

2.1. Reifikation

Teknisk set er de generiske typer ikke reified i Java. I programmeringssprogets terminologi, når en type er til stede ved kørsel, siger vi, at typen genoprettes.

De reified-typer i Java er som følger:

  • Enkle primitive typer såsom lang
  • Ikke-generiske abstraktioner som f.eks Snor eller Kan køres
  • Rå typer såsom Liste eller HashMap
  • Generiske typer, hvor alle typer er ubegrænsede jokertegn som f.eks Liste eller HashMap
  • Arrays af andre reified typer såsom String [], int [], List [], eller Kort[]

Derfor kan vi ikke bruge noget lignende Kort. Klasse fordi Kort er ikke en reified type.

3. Super Type Token

Som det viser sig, kan vi udnytte kraften i anonyme indre klasser i Java til at bevare typeoplysningerne under kompileringstid:

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

Denne klasse er abstrakt, så vi kan kun udlede underklasser fra den.

For eksempel kan vi oprette en anonym indre:

TypeReference token = ny TypeReference() {};

Konstruktøren udfører følgende trin for at bevare typeoplysningerne:

  • For det første får den generiske superklassemetadata til denne særlige forekomst - i dette tilfælde er den generiske superklasse TypeReference
  • Derefter henter og gemmer den den aktuelle typeparameter for den generiske superklasse - i dette tilfælde ville det være Kort

Denne tilgang til at bevare den generiske typeinformation er normalt kendt som super type token:

TypeReference 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 hjælp af toppe af supertype ved vi, at containertypen er Kort, og også er dens typeparametre Snor og Heltal.

Dette mønster er så berømt, at biblioteker som Jackson og rammer som Spring har deres egne implementeringer af det. Parsing af et JSON-objekt i en Kort kan opnås ved at definere den type med et supertypetoken:

TypeReference token = ny TypeReference() {}; Kort json = objectMapper.readValue (data, token);

4. Konklusion

I denne vejledning lærte vi, hvordan vi kan bruge super-type tokens til at bevare den generiske typeinformation under kørsel.

Som sædvanligt er alle eksemplerne tilgængelige på GitHub.


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