Een generieke array maken in Java

1. Inleiding

Mogelijk willen we arrays gebruiken als onderdeel van klassen of functies die generieke geneesmiddelen ondersteunen. Vanwege de manier waarop Java generieke geneesmiddelen verwerkt, kan dit moeilijk zijn.

In deze tutorial zullen we de uitdagingen begrijpen van het gebruik van generieke geneesmiddelen met arrays. Vervolgens maken we een voorbeeld van een generieke array.

We zullen ook kijken waar de Java API een soortgelijk probleem heeft opgelost.

2. Overwegingen bij het gebruik van algemene arrays

Een belangrijk verschil tussen arrays en generieke geneesmiddelen is hoe ze typecontrole afdwingen. In het bijzonder slaan arrays type-informatie op en controleren deze tijdens runtime. Generics controleren echter op typefouten tijdens het compileren en hebben geen type-informatie tijdens runtime.

De syntaxis van Java suggereert dat we mogelijk een nieuwe generieke array kunnen maken:

T [] elementen = nieuwe T [grootte];

Maar als we dit zouden proberen, zouden we een compileerfout krijgen.

Laten we het volgende overwegen om te begrijpen waarom:

openbare T [] getArray (int grootte) {T [] genericArray = nieuwe T [grootte]; // stel dat dit is toegestaan ​​return genericArray; }

Als een ongebonden generiek type T besluit om Voorwerp, onze methode tijdens runtime zal zijn:

public Object [] getArray (int size) {Object [] genericArray = new Object [size]; retourneer genericArray; }

Als we dan onze methode aanroepen en het resultaat opslaan in een Draad matrix:

String [] myArray = getArray (5);

De code compileert prima, maar mislukt tijdens runtime met een ClassCastException. Dit komt omdat we zojuist een Voorwerp[] naar een Draad[] referentie. Concreet zou een impliciete cast door de compiler niet kunnen worden geconverteerd Voorwerp[] naar ons gewenste type Draad[].

Hoewel we generieke arrays niet rechtstreeks kunnen initialiseren, is het nog steeds mogelijk om de equivalente bewerking uit te voeren als het precieze type informatie wordt geleverd door de aanroepende code.

3. Een generieke array maken

Laten we voor ons voorbeeld eens kijken naar een datastructuur met begrensde stapel MyStack, waar de capaciteit is vastgesteld op een bepaalde grootte. Omdat we willen dat de stack met elk type werkt, zou een redelijke implementatiekeuze een generieke array zijn.

Laten we eerst een veld maken om de elementen van onze stapel op te slaan, wat een generiek type array is E.:

privé E [] elementen;

Ten tweede, laten we een constructor toevoegen:

openbare MyStack (Class clazz, int capacity) {elements = (E []) Array.newInstance (clazz, capaciteit); }

Merk op hoe we gebruiken java.lang.reflect.Array # newInstance om onze generieke array te initialiseren, waarvoor twee parameters nodig zijn. De eerste parameter specificeert het type object in de nieuwe array. De tweede parameter geeft aan hoeveel ruimte er voor de array moet worden gemaakt. Als gevolg van Array # newInstance is van het type Voorwerp, we moeten het casten naar E [] om onze generieke array te maken.

We moeten ook letten op de conventie voor het benoemen van een typeparameter clazz liever dan klasse, dat is een gereserveerd woord in Java.

4. Overwegen ArrayList

4.1. Gebruik makend van ArrayList in plaats van een array

Het is vaak gemakkelijker om een ​​generiek te gebruiken ArrayList in plaats van een generieke array. Laten we eens kijken hoe we kunnen veranderen MyStack om een ArrayList.

Laten we eerst een veld maken om onze elementen op te slaan:

privélijstelementen;

Ten tweede kunnen we in onze stackconstructor de ArrayList met een initiële capaciteit:

elementen = nieuwe ArrayList (capaciteit);

Het maakt onze les eenvoudiger, omdat we geen reflectie hoeven te gebruiken. We zijn ook niet verplicht om letterlijk in een klas te passen bij het maken van onze stapel. Ten slotte, omdat we de initiële capaciteit van een ArrayListkunnen we dezelfde voordelen krijgen als een array.

Daarom hoeven we alleen arrays van generieke geneesmiddelen te construeren in zeldzame situaties of wanneer we een interface hebben met een externe bibliotheek waarvoor een array nodig is.

4.2. ArrayList Implementatie

Interessant is dat ArrayList zelf wordt geïmplementeerd met behulp van generieke arrays. Laten we naar binnen kijken ArrayList om te zien hoe.

Laten we eerst eens kijken naar het veld met lijstelementen:

voorbijgaande Object [] elementData;

Merk op ArrayList toepassingen Voorwerp als het elementtype. Aangezien ons generieke type pas bekend is tijdens de looptijd, Voorwerp wordt gebruikt als de superklasse van elk type.

Het is vermeldenswaard dat bijna alle operaties in ArrayList kunnen deze generieke array gebruiken omdat ze geen sterk getypeerde array aan de buitenwereld hoeven te bieden, behalve voor één methode - toArray!

5. Een array bouwen uit een collectie

5.1. LinkedList-voorbeeld

Laten we eens kijken naar het gebruik van generieke arrays in de Java Collections API, waar we een nieuwe array van een collectie zullen bouwen.

Laten we eerst een nieuw LinkedList met een type-argument Draad en voeg er items aan toe:

Lijstitems = nieuwe LinkedList (); items.add ("eerste item"); items.add ("tweede item"); 

Ten tweede, laten we een reeks van de items maken die we zojuist hebben toegevoegd:

String [] itemsAsArray = items.toArray (nieuwe String [0]);

Om onze array op te bouwen, de Lijst.toArray methode vereist een invoerarray. Het gebruikt deze array puur om de type-informatie op te halen om een ​​retourarray van het juiste type te maken.

In ons voorbeeld hierboven hebben we nieuwe string [0] als onze invoerarray om het resulterende Draad array.

5.2. LinkedList.toArray Implementatie

Laten we naar binnen kijken LinkedList.toArray, om te zien hoe het is geïmplementeerd in de Java JDK.

Laten we eerst eens kijken naar de handtekening van de methode:

openbare T [] toArray (T [] a)

Ten tweede, laten we eens kijken hoe een nieuwe array wordt gemaakt wanneer dat nodig is:

a = (T []) java.lang.reflect.Array.newInstance (a.getClass (). getComponentType (), grootte);

Merk op hoe het er gebruik van maakt Array # newInstance om een ​​nieuwe array te bouwen, zoals in ons eerder stackvoorbeeld. Merk ook op hoe parameter een wordt gebruikt om een ​​type aan te geven Array # newInstance. Eindelijk het resultaat van Array # newInstance wordt geworpen T [] maak een generieke array.

6. Conclusie

In dit artikel hebben we eerst gekeken naar de verschillen tussen arrays en generieke geneesmiddelen, gevolgd door een voorbeeld van het maken van een generieke array. Vervolgens hebben we laten zien hoe u een ArrayList is misschien eenvoudiger dan het gebruik van een generieke array. Ten slotte hebben we ook gekeken naar het gebruik van een generieke array in de Collections API.

Zoals altijd is de voorbeeldcode beschikbaar op GitHub.