{"id":31,"date":"2014-05-26T12:06:23","date_gmt":"2014-05-26T12:06:23","guid":{"rendered":"http:\/\/vkrastev1blog.com\/?p=31"},"modified":"2014-05-26T15:36:27","modified_gmt":"2014-05-26T15:36:27","slug":"java-generics-explained-in-short-form-with-examples","status":"publish","type":"post","link":"https:\/\/vkrastev1blog.com\/2014\/05\/26\/java-generics-explained-in-short-form-with-examples\/","title":{"rendered":"Java-generieken uitgelegd in korte vorm met voorbeelden"},"content":{"rendered":"<p>Raadpleeg deze veelgestelde vraag voor meer informatie:<\/p>\n<p><a href=\"http:\/\/www.angelikalanger.com\/GenericsFAQ\/JavaGenericsFAQ.html#SECTION1\" rel=\"nofollow\">http:\/\/www.angelikalanger.com\/GenericsFAQ\/JavaGenericsFAQ.html#SECTION1<\/a><\/p>\n<p>Hier in het kort enkele belangrijke punten uit deze FAQ.<\/p>\n<p>Voorbeeld (van een generiek type):<\/p>\n<blockquote><p><tt> klasse Paar&lt;X,Y&gt; {\u00a0<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 X eerst;<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 Y seconde;<\/tt><tt> \u00a0 openbaar paar(X a1, Y a2) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 eerste = a1;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 tweede = a2;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 public X getFirst() { return first; }<\/tt><br \/>\n<tt> \u00a0 public Y getSecond() { return tweede; }<\/tt><br \/>\n<tt> \u00a0 public void setFirst(X arg)\u00a0 { eerste = arg; }<\/tt><br \/>\n<tt> \u00a0 public void setSecond(Y arg) { seconde = arg; }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>De klas <tt> Paar<\/tt> heeft twee typeparameters <tt> X <\/tt> En <tt> Y<\/tt> .\u00a0 Ze worden vervangen door type-argumenten als het om een \u200b\u200bgeneriek type gaat <tt> Paar<\/tt> wordt ge\u00efnstantieerd. In de aangifte bijvoorbeeld <tt> Paar&lt;String, Datum&gt;<\/tt> de typeparameter <tt> X<\/tt> wordt vervangen door het argument type <tt> Snaar<\/tt> En <tt> Y<\/tt> wordt vervangen door\u00a0 <tt> Datum<\/tt> .<br \/>\nHet bereik van de id&#8217;s <tt> X <\/tt> En <tt> Y<\/tt> is<b> <i> <\/i> <\/b> de volledige definitie van de klasse.\u00a0 In dit kader de twee typeparameters <tt> X <\/tt> En <tt> Y<\/tt> worden gebruikt alsof het typen zijn (met enkele beperkingen). In het bovenstaande voorbeeld worden de typeparameters gebruikt als argument en retourneringstype van instantiemethoden en de typen instantievelden.<br \/>\nTypeparameters kunnen met grenzen worden gedeclareerd. Grenzen geven toegang tot methoden van het onbekende type waarvoor de parameter type staat. In ons voorbeeld roepen we geen methoden van het onbekende type aan <tt> X <\/tt> En <tt> Y<\/tt> . Om deze reden zijn de twee typeparameters onbegrensd.<\/p>\n<p>Voorbeeld (van een concreet geparametriseerd type):<\/p>\n<blockquote><p><tt> openbare leegte printPair(<b> <span style=\"color:#000099;\"> Paar&lt;String,Long&gt;<\/span> <\/b> paar) {<\/tt><br \/>\n<tt> \u00a0 System.out.println(\"(\"+pair.getFirst()+\",\"+pair.getSecond()+\")\");<\/tt><br \/>\n<tt> }<\/tt><tt> <b> <span style=\"color:#000099;\"> Paar&lt;String,Long&gt;<\/span> <\/b> limiet = nieuw <b> <span style=\"color:#000099;\"> Paar&lt;String,Long&gt;<\/span> <\/b> (\"maximum\",1024L);<\/tt><br \/>\n<tt> printPair(limiet);<\/tt><\/p><\/blockquote>\n<p>Voorbeeld (van een met jokertekens geparametriseerd type):<\/p>\n<blockquote>\n<blockquote><p><tt> openbare leegte printPair(<b> <span style=\"color:#000099;\"> Paar&lt;?,?&gt;<\/span> <\/b> paar) {<\/tt><br \/>\n<tt> \u00a0 System.out.println(\"(\"+pair.getFirst()+\",\"+pair.getSecond()+\")\");<\/tt><br \/>\n<tt> }<\/tt><tt> <b> <span style=\"color:#000099;\"> Paar&lt;?,?&gt;<\/span> <\/b> limiet = nieuw <b> <span style=\"color:#000099;\"> Paar&lt;String,Long&gt;<\/span> <\/b> (\"maximum\",1024L);<\/tt><br \/>\n<tt> printPair(limiet);<\/tt><\/p><\/blockquote>\n<\/blockquote>\n<p>Alle instantiaties van een generiek type delen dezelfde runtime-typerepresentatie, namelijk de representatie van het onbewerkte type. Bijvoorbeeld de instantiaties van een generiek type <tt> Lijst<\/tt> , zoals <tt> Lijst&lt;Datum&gt;<\/tt> , <tt> Lijst&lt;String&gt;<\/tt> , <tt> Lijst&lt;Lang&gt;<\/tt> , enz. hebben tijdens het compileren verschillende statische typen, maar hetzelfde dynamische type <tt> Lijst <\/tt> tijdens runtime.<\/p>\n<p>Een cast bestaat uit twee delen:<\/p>\n<ul>\n<li>een statische typecontrole uitgevoerd door de compiler tijdens het compileren en<\/li>\n<li>een dynamische typecontrole die tijdens runtime door de virtuele machine wordt uitgevoerd.<\/li>\n<\/ul>\n<p>Het statische deel sorteert onzinnige casts, die niet kunnen slagen, zoals de cast uit <tt> Snaar<\/tt> Dat <tt> Datum<\/tt> of van <tt> Lijst&lt;String&gt;<\/tt> Dat <tt> Lijst&lt;Datum&gt;<\/tt> .<\/p>\n<p>Het dynamische deel gebruikt de runtime-type-informatie en voert tijdens runtime een typecontrole uit.\u00a0 Het verhoogt een <tt> ClassCastException<\/tt> als het dynamische type van het object niet het doeltype (of een subtype van het doeltype) van de cast is. Voorbeelden van casts met een dynamische rol zijn de cast uit <tt> Voorwerp<\/tt> Dat <tt> Snaar<\/tt> of van <tt> Voorwerp<\/tt> Dat <tt> Lijst&lt;String&gt;<\/tt> .\u00a0 Dit zijn de zogenaamde downcasts, van een supertype naar een subtype.<\/p>\n<p>Voorbeelden van concrete geparametriseerde typen zijn <tt> Lijst&lt;String&gt;<\/tt> , <tt> Kaart&lt;String, Datum&gt;<\/tt> , maar niet <tt> Lijst&lt;? breidt Nummer&gt; uit<\/tt> of <tt> Kaart&lt;String,?&gt;<\/tt> .<\/p>\n<p>Soms wordt verwacht dat a <tt> Lijst&lt;Object&gt;<\/tt> zou een supertype zijn van a <tt> Lijst&lt;String&gt;<\/tt> , omdat <tt> Voorwerp<\/tt> is een supertype van <tt> Snaar<\/tt> .\u00a0 Deze verwachting komt voort uit het feit dat een dergelijk soort relatie bestaat voor arrays:\u00a0 <tt> Voorwerp[]<\/tt> is een supertype van <tt> Snaar[]<\/tt> , omdat <tt> Voorwerp<\/tt> is een supertype van <tt> Snaar<\/tt> . (Dit type relatie staat bekend als <i> covariantie<\/i> .) De super-subtype-relatie van de componenttypen strekt zich uit tot de overeenkomstige arraytypen. Een dergelijke typerelatie bestaat niet voor instantiaties van generieke typen. (Geparametriseerde typen zijn <i> niet<\/i> covariant.)<\/p>\n<p>Het ontbreken van een super-subtype-relatie tussen instantiaties van hetzelfde generieke type heeft verschillende gevolgen.\u00a0 Hier is een voorbeeld.<\/p>\n<p>Voorbeeld:<\/p>\n<p><tt> void printAll(ArrayList&lt;Object&gt; c) {<\/tt><br \/>\n<tt> \u00a0 voor (Object o: c)\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 Systeem.out.println(o);<\/tt><br \/>\n<tt> }<\/tt><tt> ArrayList&lt;String&gt; lijst = nieuwe ArrayList&lt;String&gt;();<\/tt><br \/>\n<tt> ... lijst invullen ...<\/tt><br \/>\n<tt> printAll(lijst);\u00a0\u00a0 \/\/ fout<\/tt><\/p>\n<p>A <tt> ArrayLijst&lt;String&gt;<\/tt> object kan niet als argument worden doorgegeven aan een methode die om a vraagt <tt> ArrayLijst&lt;Object&gt;<\/tt> omdat de twee typen instantiaties zijn van hetzelfde generieke type, maar voor <i> verschillend<\/i> type argumenten, en om deze reden zijn ze niet compatibel met elkaar.<\/p>\n<p>Concrete geparametriseerde typen zijn concrete instantiaties van een generiek type.\u00a0 Het lijken bijna typen; er zijn slechts een paar beperkingen.\u00a0 Ze kunnen NIET worden gebruikt voor de volgende doeleinden:<\/p>\n<ul>\n<li>voor het maken van arrays<\/li>\n<li>bij het afhandelen van uitzonderingen<\/li>\n<li>in een klasse letterlijk<\/li>\n<li>in een <tt> exemplaarvan<\/tt> uitdrukking<\/li>\n<\/ul>\n<p>Arrays die elementen bevatten waarvan het type een concreet geparameteriseerd type is, zijn illegaal.<\/p>\n<p>Voorbeeld (van illegaal arraytype):<\/p>\n<p><tt> statische leegtetest() {<\/tt><br \/>\n<tt> \u00a0 <b> <span style=\"color:#660000;\"> Paar&lt;Geheel getal,Geheel getal&gt;[]<\/span> <\/b> intPairArr = nieuw <b> <span style=\"color:#660000;\"> Paar&lt;Geheel getal,Geheel getal&gt;[10]<\/span> <\/b> ; <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 addElements(intPairArr);\u00a0<\/tt><br \/>\n<tt> \u00a0 Paar&lt;Geheel getal,Geheel getal&gt; paar = intPairArr[1];<\/tt><br \/>\n<tt> \u00a0 Geheel getal i = paar.getFirst();<\/tt><br \/>\n<tt> \u00a0 paar.setSecond(i);<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> statische leegte addElements(<b> Voorwerp[]<\/b> objArr) {<\/tt><br \/>\n<tt> \u00a0 objArr[0] = nieuw Paar&lt;Geheel getal,Geheel getal&gt;(0,0);<\/tt><br \/>\n<tt> \u00a0 objArr[1] = nieuw Pair&lt;String,String&gt;(\"\",\"\");\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ zou moeten mislukken met ArrayStoreException<\/tt><br \/>\n<tt> }<\/tt><\/p>\n<p>De compiler verbiedt het maken van arrays waarvan het componenttype een concreet geparametriseerd type is, zoals <tt> Paar&lt;Geheel getal,Geheel getal&gt;<\/tt> in ons voorbeeld.\u00a0 We hebben in het voorgaande artikel besproken waarom het redelijk is dat de compiler een kwalificeert<span style=\"color:#000000;\"> <tt> Paar&lt;Geheel getal,Geheel getal&gt;[]<\/tt> <\/span> als illegaal.\u00a0 Het belangrijkste probleem is dat de compiler en het runtimesysteem ervoor moeten zorgen dat een array een <i> homogeen<\/i> reeks elementen van hetzelfde type.\u00a0 E\u00e9n van de typecontroles, namelijk de array-store-check die tijdens runtime door de virtuele machine wordt uitgevoerd, slaagt er niet in de inbreukmakende invoeging van een buitenaards element te detecteren. In het voorbeeld is de tweede invoeging in de <tt> elementen toevoegen<\/tt> methode zou moeten mislukken, omdat ze een paar strings aan een array van integrale waarden toevoegden, maar het mislukt niet zoals verwacht. De redenen zijn in het vorige bericht besproken.<\/p>\n<p>Als we geen arrays kunnen gebruiken die elementen bevatten waarvan het type een concreet geparameteriseerd type is, wat gebruiken we dan als tijdelijke oplossing?<\/p>\n<p>Laten we drie mogelijke oplossingen bekijken:<\/p>\n<ul>\n<li>reeks ruwe soorten<\/li>\n<li>array van een onbegrensd, met jokertekens geparametriseerd type<\/li>\n<li>verzameling in plaats van array<\/li>\n<\/ul>\n<p>Hoewel arrays van typen met concrete parameters illegaal zijn, zijn verzamelingen van typen met concrete parameters toegestaan.<\/p>\n<p>Een met jokertekens geparametriseerd type is een instantiatie van een generiek type waarbij ten minste \u00e9\u00e9n typeargument een jokerteken is.\u00a0 Voorbeelden van met jokertekens geparametriseerde typen zijn <tt> Collectie&lt;?&gt;<\/tt> , <tt> Lijst&lt;? breidt Nummer&gt; uit<\/tt> , <tt> Vergelijker&lt;? superString&gt;<\/tt> En <tt> Paar&lt;String,?&gt;<\/tt> . Een met jokertekens geparametriseerd type duidt een familie van typen aan die concrete instantiaties van een generiek type omvat.\u00a0 Het soort jokerteken dat wordt gebruikt, bepaalt welke concrete geparametriseerde typen tot de familie behoren.\u00a0 Bijvoorbeeld het met jokertekens geparametriseerde type <tt> Collectie&lt;?&gt;<\/tt> geeft de familie aan van alle instantiaties van de <tt> Verzameling<\/tt> interface, ongeacht het typeargument.\u00a0 Het met jokertekens geparametriseerde type <tt> Lijst&lt;? breidt Nummer&gt; uit<\/tt> geeft de familie van alle lijsttypen aan waarvan het elementtype een subtype is\u00a0 <tt> Nummer<\/tt> .\u00a0 Het met jokertekens geparametriseerde type <tt> Vergelijker&lt;? superString&gt;<\/tt> is de familie van alle instantiaties van de <tt> Comparator<\/tt> interface voor type-argumenttypen die supertypes zijn van <tt> Snaar.<\/tt><\/p>\n<p><strong><em>Een met jokertekens geparametriseerd type is geen type in de reguliere zin (anders dan een niet-geparametriseerde klasse\/interface of een onbewerkt type).<\/em> <\/strong><\/p>\n<p>Geparametriseerde typen met jokertekens kunnen worden gebruikt voor typen (zoals niet-geparametriseerde klassen en interfaces):<\/p>\n<ul>\n<li>als argument- en return-methoden<\/li>\n<li>als type veld of lokale referentievariabele<\/li>\n<li>als componenttype van een arrayas-typeargument van andere geparametriseerde typen<\/li>\n<li>als doeltype bij afgietsels<\/li>\n<\/ul>\n<p>Niet alleen typen kunnen generiek zijn, maar methoden kunnen ook generiek zijn. Statische en niet-statische methoden, evenals constructors, kunnen typeparameters hebben. De syntaxis voor het declareren van de formele typeparameters is vergelijkbaar met de syntaxis voor generieke typen. De sectie voor typeparameters wordt begrensd door punthaken en verschijnt v\u00f3\u00f3r het retourtype van de methode. De syntaxis en betekenis ervan zijn identiek aan de typeparameterlijst van een generiek type.<\/p>\n<p>Hier is het voorbeeld van een generieke <tt> maximaal<\/tt> methode die de grootste waarde berekent in een verzameling elementen van een onbekend type <tt> A<\/tt> .<\/p>\n<p>Voorbeeld (van een generieke methode):<\/p>\n<blockquote><p><tt> klasse Collecties {<\/tt><br \/>\n<tt> \u00a0 publiek statisch <b> <span style=\"color:#000099;\"> &lt;A breidt Vergelijkbaar&lt;A&gt;&gt; A uit<\/span> <\/b> max(Verzameling&lt;<b> <span style=\"color:#000099;\"> A<\/span> <\/b> &gt; xs) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 Iterator&lt;<b> <span style=\"color:#000099;\"> A<\/span> <\/b> &gt; xi = xs.iterator();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 <b> <span style=\"color:#000099;\"> A<\/span> <\/b> w = xi.volgende();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 terwijl (xi.hasNext()) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#000099;\"> A<\/span> <\/b> x = xi.volgende();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 als (w.vergelijk(x) &lt; 0) w = x;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 retour w;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }\u00a0<\/tt><\/p><\/blockquote>\n<p>De <tt> maximaal<\/tt> methode heeft \u00e9\u00e9n typeparameter, genaamd<tt> A<\/tt> .\u00a0 Het is een tijdelijke aanduiding voor het elementtype van de verzameling waarop de methode werkt. De parameter type heeft een grens; het moet een type zijn dat een subtype is van <tt> Vergelijkbaar&lt;A&gt;<\/tt><\/p>\n<p>Voorbeeld (van hetzelfde generieke type, deze keer <i> met<\/i> grenzen):<\/p>\n<blockquote><p><tt> openbare interface Vergelijkbaar&lt;T&gt; {<\/tt><br \/>\n<tt> \u00a0 public int CompareTo(T arg);<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> openbare klasse TreeMap&lt;Key <b> <span style=\"color:#000066;\"> breidt Vergelijkbare&lt;Key&gt; uit<\/span> <\/b> ,Gegevens&gt;{<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 statische klasse Entry&lt;K,V&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 K-sleutel;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 V-waarde;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Invoer&lt;K,V&gt; links = nul;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Invoer&lt;K,V&gt; rechts = nul;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Vermelding&lt;K,V&gt; ouder;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 tijdelijke Entry&lt;Key,Data&gt; root = null;<\/tt><br \/>\n<tt> \u00a0 ...<\/tt><br \/>\n<tt> \u00a0 priv\u00e9-invoer&lt;Key,Data&gt; getEntry(sleutelsleutel) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Invoer&lt;Sleutel,Gegevens&gt; p = root;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Sleutel k = sleutel;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 terwijl (p!= nul) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 int cmp = k.<b> <span style=\"color:#990000;\"> vergelijkTo(p.key)<\/span> <\/b> ;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 als (cmp == 0)<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 retour p;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 anders als (cmp &lt; 0)<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 p = p.links;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 anders\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 p = p.rechts;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 retourneer nul;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 public boolean containKey(Sleutelsleutel) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 return getEntry(sleutel) != null;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>In het bovenstaande voorbeeld is dit de parameter type <tt> Sleutel<\/tt> heeft de grens <tt> Vergelijkbaar&lt;Sleutel&gt;<\/tt> .\u00a0 Het specificeren van een grens heeft twee effecten:<\/p>\n<ul>\n<li><i> Het geeft toegang tot de methoden die de grens specificeert<\/i> .\u00a0 In het voorbeeld de grens <tt> Vergelijkbaar&lt;Sleutel&gt; <\/tt> geeft toegang tot de <tt> vergelijkTo<\/tt> methode die we willen gebruiken bij de implementatie van onze <tt> Boomkaart<\/tt> klas.<\/li>\n<\/ul>\n<ul>\n<li><i> Alleen typen &#8220;binnen de grenzen&#8221; kunnen worden gebruikt voor het instanti\u00ebren van het generieke type.<\/i> \u00a0 In het voorbeeld is een geparametriseerd type zoals <tt> Boomkaart&lt;Number,String&gt;<\/tt> zou worden afgewezen, omdat het type <tt> Nummer<\/tt> is geen subtype van <tt> Vergelijkbaar&lt;Nummer&gt;<\/tt> .\u00a0 Een geparametriseerd type zoals <tt> Boomkaart&lt;String,String&gt;<\/tt> zou worden geaccepteerd, omdat het type String binnen de grenzen valt, d.w.z. een subtype is van <tt> Vergelijkbaar&lt;String&gt;<\/tt> .<\/li>\n<\/ul>\n<p>Alle klassen, interfaces en enum-typen kunnen worden gebruikt als type-parametergebonden, inclusief geneste en innerlijke typen.\u00a0 Noch primitieve typen, noch arraytypen mogen worden gebruikt als typeparametergrens.<\/p>\n<p>Voorbeelden (van type parametergrenzen):<\/p>\n<blockquote><p><tt> klasse X0 &lt;T breidt uit <b> <span style=\"color:#000099;\"> int<\/span> <\/b> &gt; { ... }\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> klasse X1 &lt;T breidt zich uit <b> <span style=\"color:#000099;\"> Voorwerp[]<\/span> <\/b> &gt; { ... } <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> klasse X2 &lt;T breidt zich uit <b> <span style=\"color:#000099;\"> Nummer<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> klasse X3 &lt;T breidt zich uit <b> <span style=\"color:#000099;\"> Snaar<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> klasse X4 &lt;T breidt uit <b> <span style=\"color:#000099;\"> Uitvoerbaar<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> klasse X5 &lt;T breidt zich uit <b> <span style=\"color:#000099;\"> Draad.State<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> klasse X6 &lt;T breidt zich uit <b> <span style=\"color:#000099;\"> Lijst<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> klasse X7 &lt;T breidt zich uit <b> <span style=\"color:#000099;\"> Lijst&lt;String&gt;<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> klasse X8 &lt;T breidt zich uit <b> <span style=\"color:#000099;\"> Lijst&lt;? breidt Nummer&gt; uit<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> klasse X9 &lt;T breidt zich uit <b> <span style=\"color:#000099;\"> Vergelijkbaar&lt;? supernummer&gt;<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> klasse X10&lt;T breidt zich uit <b> <span style=\"color:#000099;\"> Kaart.Invoer&lt;?,?&gt;<\/span> <\/b> &gt; { ... }<\/tt><\/p><\/blockquote>\n<p>Het codevoorbeeld laat zien dat primitieve typen zoals <tt> int<\/tt> en arraytypen zoals <tt> Voorwerp[] <\/tt> zijn niet toegestaan \u200b\u200bals typeparametergebonden.<\/p>\n<p>Klassetypen, zoals <tt> Nummer<\/tt> of <tt> Snaar<\/tt> en interfacetypen, zoals <tt> Uitvoerbaar<\/tt> , zijn toegestaan \u200b\u200bals typeparametergebonden.<\/p>\n<p>Enum-typen, zoals <tt> Draad.State<\/tt> zijn ook toegestaan \u200b\u200bals typeparametergebonden. <tt> Draad.State<\/tt> is een voorbeeld van een genest type dat wordt gebruikt als typeparametergebonden.\u00a0 Ook niet-statische binnenuitvoeringen zijn toegestaan.<\/p>\n<p>Ruwe typen zijn toegestaan \u200b\u200bals typeparametergebonden; <tt> <span style=\"color:#000000;\"> Lijst<\/span> <\/tt> is een voorbeeld.<\/p>\n<p>Geparametriseerde typen zijn toegestaan \u200b\u200bals typeparametergebonden, inclusief concrete geparametriseerde typen zoals <tt> Lijst&lt;String&gt;<\/tt> , begrensde typen met jokertekens, zoals <tt> Lijst&lt;? breidt Nummer&gt; uit<\/tt> En <tt> Vergelijkbaar&lt;? superLong&gt;<\/tt> en onbegrensde typen met jokertekens, zoals <tt> Kaart.Invoer&lt;?,?&gt;<\/tt> .\u00a0 Een grens die een met jokertekens geparametriseerd type is, staat als typeargument alle typen toe die behoren tot de typefamilie die door het jokerteken wordt aangegeven.\u00a0 De met jokertekens geparametriseerde typegrens geeft slechts beperkte toegang tot velden en methoden; de beperkingen zijn afhankelijk van het soort wildcard.<\/p>\n<p>Voorbeeld (van met jokertekens geparametriseerd type als type parameter gebonden):<\/p>\n<blockquote><p><tt> klasse X&lt;<b> <span style=\"color:#000099;\"> T breidt Lijst&lt; uit? breidt Nummer&gt; uit<\/span> <\/b> &gt; {<\/tt><br \/>\n<tt> \u00a0 public void someMethod(T t) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 t.add(nieuw lang(0L));\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 Getal n = t.verwijder(0);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> klasse Test {<\/tt><br \/>\n<tt> \u00a0 public static void main(String[] args) {<\/tt><br \/>\n<tt> <b> <span style=\"color:#660000;\"> \u00a0\u00a0\u00a0\u00a0 <\/span> <\/b> <span style=\"color:#000000;\"> X&lt;ArrayLijst&lt;<\/span> <b> <span style=\"color:#000099;\"> Lang<\/span> <\/b> <span style=\"color:#000000;\"> &gt;&gt; x1 = nieuwe X&lt;ArrayList&lt;Long&gt;&gt;();\u00a0<\/span> <\/tt><br \/>\n<tt> <span style=\"color:#000000;\"> \u00a0\u00a0\u00a0\u00a0 X&lt;ArrayLijst&lt;<\/span> <b> <span style=\"color:#000099;\"> Snaar<\/span> <\/b> <span style=\"color:#000000;\"> &gt;&gt; x2 = nieuwe X&lt;ArrayList&lt;String&gt;&gt;(); <\/span> <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Referentievariabelen van het type<tt> T <\/tt> (de typeparameter) worden behandeld als referentievariabelen van het jokertekentype (de typeparameter gebonden).\u00a0 In ons voorbeeld is de consequentie dat de compiler het aanroepen van methoden afwijst die een argument aannemen van het &#8220;onbekende&#8221; type waarvoor de parameter type staat, zoals <tt> Lijst.toevoegen<\/tt> , omdat de grens een met jokertekens geparametriseerd type is met een bovengrens.<br \/>\nTegelijkertijd de grens <tt> Lijst&lt;? breidt Nummer&gt; uit<\/tt> bepaalt de typen die kunnen worden gebruikt als typeargumenten. De compiler accepteert alle typeargumenten die tot de typefamilie behoren <tt> Lijst&lt;? breidt Nummer&gt; uit<\/tt> , dat wil zeggen, alle subtypen van <tt> Lijst<\/tt> met een type-argument dat een subtype is van <tt> Nummer<\/tt> .<\/p>\n<p>Een typeparameter kan worden gebruikt als grens voor een andere typeparameter.<\/p>\n<p>Voorbeeld (van een typeparameter die wordt gebruikt als een typeparametergebonden):<\/p>\n<blockquote><p><tt> klasse Drievoudig<b> &lt;T&gt;<\/b> {<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 T fst, snd, trd;<\/tt><br \/>\n<tt> \u00a0 openbare &lt;<b> U<\/b> <b> <span style=\"color:#000099;\"> verlengt T<\/span> <\/b> , <b> V <span style=\"color:#000099;\"> verlengt T<\/span> <\/b> , <b> W <span style=\"color:#000099;\"> verlengt T<\/span> <\/b> &gt; Drievoudig(U arg1, V arg2, W arg3) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 fst = arg1;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 snd = arg2;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 trd = arg3;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>In dit voorbeeld de parameter type <tt> T<\/tt> van de geparametriseerde klasse wordt gebruikt als grens van de typeparameters <tt> U<\/tt> ,\u00a0 <tt> V<\/tt> En <tt> W<\/tt> van een geparametriseerde instantiemethode van die klasse.<\/p>\n<p>Verdere mogelijkheden voor het gebruik van typeparameters als grenzen van andere typeparameters zijn onder meer situaties waarin een genest type is gedefinieerd binnen een generiek type of een lokale klasse is gedefinieerd binnen een generieke methode.\u00a0 Het is zelfs toegestaan \u200b\u200bom een \u200b\u200btypeparameter te gebruiken als grens van een andere typeparameter in dezelfde typeparametersectie.<\/p>\n<p>Een grens die een klasse is, geeft toegang tot al zijn openbare leden, dat wil zeggen openbare velden, methoden en geneste typen. Alleen constructors worden niet toegankelijk gemaakt, omdat er geen garantie is dat een subklasse van de bound dezelfde constructors heeft als de bound.<\/p>\n<p>Voorbeeld (van een klasse die wordt gebruikt als grens van een typeparameter):<\/p>\n<blockquote><p><tt> openbare klasse <span style=\"color:#000000;\"> SuperKlasse<\/span> {<\/tt><tt> \u00a0\u00a0\u00a0 \/\/ statische leden<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 openbare opsomming EnumType {DIT, DAT}<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 publiek statisch Object staticField;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 openbare statische leegte staticMethod() { ... }<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0 \/\/ niet-statische leden<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 openbare klasse InnerClass { ... }<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 openbaar object nonStaticField;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 public void nonStaticMethod() { ... }<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0 \/\/ constructeurs<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 openbare SuperKlasse() { ... }<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0 \/\/ priv\u00e9 leden<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 priv\u00e9-object privateField;\u00a0<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p>\n<p><tt> openbare eindklasse SomeClass&lt;T breidt zich uit <b> <span style=\"color:#006600;\"> SuperKlasse<\/span> <\/b> &gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 priv\u00e9 T-object;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 publiek SomeClass(T t) {object = t; }\u00a0<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0 openbare tekenreeks toString() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 opbrengst<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"statisch genest type\u00a0\u00a0\u00a0: \"+T.EnumType.class+\"\\n\"\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"statisch veld\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : \"+T.staticField+\"\\n\"<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"statische methode\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : \"+T.staticMethod()+\"\\n\"<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"niet-statisch genest type: \"+T.InnerClass.class+\"\\n\"<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"niet-statisch veld\u00a0\u00a0\u00a0\u00a0\u00a0 : \"+object.nonStaticField+\"\\n\"<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"niet-statische methode\u00a0\u00a0\u00a0\u00a0 : \"+object.nonStaticMethod()+\"\\n\"<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"constructor\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : \"+(nieuwe T())+\"\\n\"\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ fout<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"priv\u00e9lid\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : \"+object.privateField+\"\\n\"\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ fout\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>De grens <tt> SuperKlasse<\/tt> geeft toegang tot de geneste typen, statische velden en methoden en niet-statische velden en methoden.\u00a0 Alleen de constructor is niet toegankelijk.\u00a0 Dit komt omdat constructors niet worden ge\u00ebrfd. Elke subklasse definieert zijn eigen constructors en hoeft de constructors van zijn superklasse niet te ondersteunen.\u00a0 Er is dus geen garantie dat een subklasse van <tt> SuperKlasse<\/tt> zal dezelfde constructor hebben als zijn superklasse.<\/p>\n<p>De context waarin<tt> Enum&lt;E breidt Enum&lt;E&gt;&gt; uit<\/tt> &#8221; verschijnt is de verklaring van de <tt> Enum<\/tt> klasse in pakket <tt> java.lang<\/tt> :<\/p>\n<blockquote><p><tt> openbare abstracte klasse <b> Enum&lt;E breidt Enum&lt;E&gt;&gt; uit<\/b> {<\/tt><br \/>\n<tt> \u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Het soort <tt> Enum<\/tt> is de gemeenschappelijke basisklasse van alle opsommingstypen.\u00a0 In Java is een opsommingstype zoals <tt> Kleur<\/tt> wordt vertaald naar een klasse <tt> Kleur<\/tt> dat strekt zich uit <tt> Enum&lt;Kleur&gt;<\/tt> . Het doel van de superklasse <tt> Enum<\/tt> is om functionaliteit te bieden die gemeenschappelijk is voor alle opsommingstypen.<\/p>\n<p>Hier is een schets van klasse <tt> Enum<\/tt> :<\/p>\n<blockquote><p><tt> openbare abstracte klasse <b> Enum&lt;<span style=\"color:#000099;\"> E<\/span> breidt Enum&lt;E&gt;&gt; uit<\/b> implementeert Vergelijkbaar&lt;<b> <span style=\"color:#000099;\"> E<\/span> <\/b> &gt;, serialiseerbaar {<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 uiteindelijke tekenreeksnaam;<\/tt><br \/>\n<tt> \u00a0 openbare finale Stringnaam() { ... }<\/tt><tt> \u00a0 priv\u00e9 finale int rangtelwoord;<\/tt><br \/>\n<tt> \u00a0 publieke finale int ordinal() { ... }<\/tt><\/p>\n<p><tt> \u00a0 protected Enum(Stringnaam, int rangtelwoord) { ... }<\/tt><\/p>\n<p><tt> \u00a0 public String\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 toString() { ... }<\/tt><br \/>\n<tt> \u00a0 public final boolean is gelijk aan (Object anders) { ... }<\/tt><br \/>\n<tt> \u00a0 openbare finale int hashCode() { ... }<\/tt><br \/>\n<tt> \u00a0 beschermde uiteindelijke Objectkloon() gooit CloneNotSupportedException { ... }<\/tt><br \/>\n<tt> \u00a0 openbare finale int CompareTo(<b> <span style=\"color:#000099;\"> E<\/span> <\/b> o) { ... }<\/tt><\/p>\n<p><tt> \u00a0 openbare finale Class&lt;<b> <span style=\"color:#000099;\"> E<\/span> <\/b> &gt; getDeclaringClass() { ... }<\/tt><br \/>\n<tt> \u00a0 openbare statische &lt;T breidt Enum&lt;T&gt;&gt; T waardeOf(Class&lt;T&gt; enumType, String naam) { ... }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Het verrassende kenmerk in de verklaring &#8220;<tt> Enum&lt;E breidt Enum&lt;E&gt;&gt; uit<\/tt> &#8221; is het feit dat de nieuw gedefinieerde klasse <tt> Enum<\/tt> en de nieuw gedefinieerde typeparameter <tt> E <\/tt> verschijnen binnen de grens van dezelfde typeparameter.\u00a0 Het betekent dat de <tt> Enum<\/tt> type moet worden ge\u00efnstantieerd voor een van zijn subtypen.\u00a0 Om te begrijpen waarom dit logisch is, moet je bedenken dat elk enum-type wordt vertaald in een subtype van <tt> Enum<\/tt> .<\/p>\n<p>Hier is het gekunstelde enum-type <tt> Kleur<\/tt> :<\/p>\n<blockquote><p><tt> opsomming <b> Kleur<\/b> {ROOD, BLAUW, GROEN}<\/tt><\/p><\/blockquote>\n<p>De compiler vertaalt het naar de volgende klasse:<\/p>\n<blockquote><p><tt> openbare eindklasse <b> Kleur<\/b> strekt zich uit <b> Enum&lt;Kleur&gt;<\/b> {<\/tt><br \/>\n<tt> \u00a0 openbare statische definitieve kleur[]-waarden() { return (kleur[])$VALUES.clone(); }<\/tt><br \/>\n<tt> \u00a0 public static KleurwaardeOf(Stringnaam) { ... }<\/tt><tt> \u00a0 priv\u00e9 Kleur(String s, int i) { super(s, i); }<\/tt><\/p>\n<p><tt> \u00a0 openbare statische finale Kleur ROOD;<\/tt><br \/>\n<tt> \u00a0 openbare statische finale Kleur BLAUW;<\/tt><br \/>\n<tt> \u00a0 openbare statische finale Kleur GROEN;<\/tt><\/p>\n<p><tt> \u00a0 priv\u00e9 statische uiteindelijke kleur $VALUES[];<\/tt><\/p>\n<p><tt> \u00a0 statisch {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 ROOD = nieuwe kleur(\"ROOD\", 0);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 BLAUW = nieuwe kleur(\"BLAUW\", 1);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 GROEN = nieuwe kleur(\"GROEN\", 2);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 $VALUES = (nieuwe kleur[] { ROOD, BLAUW, GROEN });<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>De erfenis heeft tot gevolg dat de <tt> Kleur<\/tt> type erft alle methoden die erin zijn ge\u00efmplementeerd <tt> Enum&lt;Kleur&gt;<\/tt> .\u00a0 Onder hen bevindt zich de <tt> vergelijkTo<\/tt> methode.\u00a0 De <tt> Kleur. vergelijkTo<\/tt> methode zou waarschijnlijk a moeten nemen <tt> Kleur<\/tt> als argument.\u00a0 Om dit mogelijk te maken, klasse <tt> Enum<\/tt> is generiek en de <tt> Enum.vergelijkTo<\/tt> methode duurt <tt> Enum<\/tt> &#8216;s typeparameter <tt> E <\/tt> als argument.\u00a0 Als resultaat typt u <tt> Kleur<\/tt> afgeleid van <tt> Enum&lt;Kleur&gt;<\/tt> erft een <tt> vergelijkTo<\/tt> methode die een <tt> Kleur<\/tt> zoals en argument, precies zoals het hoort.<br \/>\nAls we de verklaring ontleden &#8220;<tt> Enum&lt;E breidt Enum&lt;E&gt;&gt; uit<\/tt> &#8221; we kunnen zien dat dit patroon verschillende aspecten heeft.<\/p>\n<p>Ten eerste is er het feit dat de parameter type gebonden het type zelf is: &#8220;<tt> <b> Enum<\/b> &lt;E breidt uit <b> Enum<\/b> &lt;E&gt;&gt;<\/tt> &#8220;. Het zorgt ervoor dat alleen subtypen van type zijn <tt> Enum<\/tt> zijn toegestaan \u200b\u200bals typeargumenten. (Theoretisch, typ <tt> Enum<\/tt> zou op zichzelf kunnen worden ge\u00efnstantieerd, zoals in <tt> Enum&lt;ENum&gt;<\/tt> , maar dit is zeker niet de bedoeling en het is moeilijk een situatie voor te stellen waarin een dergelijke instantiatie nuttig zou zijn.)<\/p>\n<p>Ten tweede is er het feit dat het parametergebonden type het geparametriseerde type is <tt> Enum<b> &lt;E&gt;<\/b> <\/tt> , die de parameter type gebruikt <tt> E<\/tt> als het typeargument van de grens. Deze declaratie zorgt ervoor dat de overervingsrelatie tussen een subtype en een instantiatie van <tt> Enum<\/tt> is van de vorm<tt> X breidt Enum&lt;X&gt; uit<\/tt> &#8220;. Een subtype zoals &#8220;<tt> X breidt Enum&lt;Y&gt; uit<\/tt> &#8221; kan niet worden gedeclareerd vanwege het argument type <tt> Y<\/tt> zou niet binnen de perken blijven; alleen subtypes van <tt> Enum&lt;X&gt;<\/tt> zijn binnen de perken.<\/p>\n<p>In de derde plaats is er het feit dat <tt> Enum<\/tt> is in de eerste plaats generiek.\u00a0 Het betekent dat sommige van de methoden van klasse <tt> Enum<\/tt> neem een \u200b\u200bargument of retourneer een waarde van een onbekend type (of afhankelijk van een onbekend type). Zoals we al weten, zal dit onbekende type later een subtype zijn <tt> X<\/tt> van <tt> Enum&lt;X&gt;<\/tt> .\u00a0 Daarom in het geparametriseerde type <tt> Enum&lt;X&gt;<\/tt> Bij deze methoden is het subtype betrokken <tt> X<\/tt> , en ze worden overgenomen in het subtype <tt> X<\/tt> .\u00a0 De <tt> vergelijkTo<\/tt> methode is een voorbeeld van een dergelijke methode; het wordt ge\u00ebrfd van de superklasse in elke subklasse en heeft in elk geval een subklasse-specifieke handtekening.<\/p>\n<p>Kortom, de verklaring &#8220;<tt> Enum&lt;E breidt Enum&lt;E&gt;&gt; uit<\/tt> &#8221; kan worden ontcijferd als: <tt> Enum<\/tt> is een generiek type dat alleen kan worden ge\u00efnstantieerd voor zijn subtypen, en die subtypen zullen een aantal nuttige methoden erven, waarvan sommige subtype-specifieke argumenten gebruiken (of anderszins afhankelijk zijn van het subtype).<\/p>\n<p><b>Ondergrenstypeparameters van klassen<\/b><\/p>\n<p>Typeparameters kunnen verschillende grenzen hebben, zoals in <tt> klasse Box&lt;T breidt Nummer&gt; uit {...}<\/tt> . Maar een typeparameter kan geen ondergrens hebben, dat wil zeggen een constructie zoals <tt> klasse Box&lt;T <b> Geweldig<\/b> Nummer&gt; {...}<\/tt> is niet toegestaan.\u00a0 Waarom niet?\u00a0 Het antwoord is: het heeft geen zin, want als het toegestaan \u200b\u200bwas, zou je er niets mee kopen.\u00a0 Laten we eens kijken waarom ondergrenstypeparameters van klassen verwarrend zijn door te onderzoeken wat een bovengrens voor een typeparameter betekent.<\/p>\n<p>De bovengrens voor een typeparameter heeft drie effecten:<\/p>\n<ol>\n<ol>\n<li><b> <i> Beperkte instantiatie.<\/i> <\/b> De bovengrens beperkt de set typen die kunnen worden gebruikt voor het instanti\u00ebren van het generieke type.\u00a0 Als we verklaren a <tt> klasse Box&lt;T breidt Nummer&gt; uit {...} <\/tt> dan zou de compiler ervoor zorgen dat alleen subtypen van <tt> Nummer<\/tt> kan worden gebruikt als typeargument.\u00a0 Dat wil zeggen, een <tt> Doos&lt;Nummer&gt;<\/tt> of een <tt> Doos&lt;Lang&gt;<\/tt> is toegestaan, maar a <tt> Vak&lt;Object&gt;<\/tt> of <tt> Vak&lt;String&gt;<\/tt> zou worden afgewezen<\/li>\n<\/ol>\n<\/ol>\n<p>Voorbeeld (van beperkte instantiatie vanwege een bovengrens voor een typeparameter):<br \/>\n<tt> klasse Box&lt;T breidt Nummer&gt; uit {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 T-waarde;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 openbare Box(T t) { waarde = t; }\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }\u00a0<\/tt><tt> klasse Test {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 public static void main(String[] args) {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Box&lt;Long&gt; boxOfLong = nieuwe Box&lt;Long&gt;(0L);\u00a0\u00a0 <b> \/\/ prima<\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Box&lt;String&gt; boxOfString = nieuwe Box&lt;String&gt;(\"\"); <b> <span style=\"color:#330000;\"> \/\/ fout: String ligt niet binnen de grenzen<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p>\n<ol>\n<li><b> <i> Toegang tot niet-statische leden. <\/i> <\/b> De bovengrens geeft toegang tot alle openbare niet-statische methoden en velden van de bovengrens.\u00a0 Bij de uitvoering van onze <tt> klasse Box&lt;T breidt Nummer&gt; uit {...}<\/tt> we kunnen alle openbare niet-statische methoden aanroepen die in de klasse zijn gedefinieerd <tt> Nummer<\/tt> , zoals <tt> intWaarde()<\/tt> bijvoorbeeld.\u00a0 Zonder de bovengrens zou de compiler een dergelijke aanroep afwijzen. Voorbeeld (van toegang tot niet-statische leden vanwege een bovengrens voor een typeparameter):<\/li>\n<\/ol>\n<p><tt> klasse Box&lt;T breidt Nummer&gt; uit {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 T-waarde;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 openbare Box(T t) { waarde = t; }\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 public int increment() {retourwaarde.intValue()+1; } <b> \/\/ &lt;= zou een fout zijn zonder de nummergrens<\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }\u00a0<\/tt><\/p>\n<ol>\n<ol>\n<li><b> <i> Typ Wissen. <\/i> <\/b> De meest linkse bovengrens wordt gebruikt voor het wissen van het type en vervangt de typeparameter in de bytecode.\u00a0 In onze <tt> klasse Box&lt;T breidt Nummer&gt; uit {...}<\/tt> alle voorkomen van <tt> T<\/tt> vervangen door de bovengrens <tt> Nummer<\/tt> .\u00a0 Bijvoorbeeld als klasse <tt> Doos<\/tt> heeft een priv\u00e9veld van type <tt> T<\/tt> en een methode <tt> ongeldige set (T-inhoud) <\/tt> voor het instellen van dit priv\u00e9veld, dan zou het veld van het type zijn <tt> Nummer<\/tt> na het wissen van het type en de methode zou worden vertaald naar een methode <tt> void set (nummerinhoud)<\/tt> .<\/li>\n<\/ol>\n<\/ol>\n<p>Voorbeeld (van gebruik van de bovengrens voor een typeparameter bij het wissen van type &#8211; <i> voor<\/i> soort wissen):<br \/>\n<tt> klasse Box&lt;<b> T breidt Nummer uit<\/b> &gt; {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 <b> T<\/b> waarde;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 openbare box(<b> T<\/b> t) { waarde = t; }\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }\u00a0<\/tt><\/p>\n<ol>\n<ol>Voorbeeld (van gebruik van de bovengrens voor een typeparameter bij het wissen van type &#8211;<\/ol>\n<\/ol>\n<p><i> na<\/i><\/p>\n<ol>\n<ol>soort wissen):<\/ol>\n<\/ol>\n<p>&nbsp;<\/p>\n<p><tt> klasse Box {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 <b> Nummer<\/b> waarde;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 openbare box(<b> Nummer<\/b> t) { waarde = t; }\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p>\n<ol>Bovendien verschijnt de meest linkse bovengrens op andere locaties, zoals automatisch ingevoegde afgietsels en brugmethoden.<\/ol>\n<p>Als er ondergrenzen zouden worden toegestaan \u200b\u200bvoor typeparameters, welke bijwerkingen zouden of zouden deze dan moeten hebben? Als een constructie zoals <tt> klasse Box&lt;T <b> Geweldig<\/b> Nummer&gt; {...} <\/tt> waren toegestaan, wat zou dat betekenen?\u00a0 Wat zouden de drie bijwerkingen van een hogere parametergrens &#8211; beperkte instantiatie, toegang tot niet-statisch lid, typeverwijdering &#8211; betekenen voor een ondergrens?<\/p>\n<p><i> Beperkte instantiaties. <\/i> De compiler zou de set typen kunnen beperken die kunnen worden gebruikt voor het instanti\u00ebren van het generieke type met een ondergrenstypeparameter.\u00a0 De compiler kan bijvoorbeeld instantiaties toestaan \u200b\u200bzoals <tt> Doos&lt;Nummer&gt;<\/tt> En <tt> Vak&lt;Object&gt;<\/tt> van een <tt> Doos&lt;T <b> Geweldig<\/b> Nummer&gt; <\/tt> en instantiaties zoals <tt> Doos&lt;Lang&gt;<\/tt> of <tt> Doos&lt;Kort&gt;<\/tt> .\u00a0 Dit zou een effect zijn dat in lijn ligt met het restrictieve neveneffect dat is beschreven voor de hogere parametergrenzen.<\/p>\n<p><i> Toegang tot niet-statische leden. <\/i> Een lagere parametergrens voor het type geeft geen toegang tot bepaalde methoden die verder gaan dan die welke van de klasse zijn ge\u00ebrfd <tt> Voorwerp<\/tt> . In het voorbeeld van <tt> Doos&lt;T <b> Geweldig<\/b> Nummer&gt; <\/tt> de supertypes van <tt> Nummer<\/tt> hebben niets met elkaar gemeen, behalve dat het referentietypes zijn en dus subtypes ervan <tt> Voorwerp<\/tt> .\u00a0 De compiler kan er niet van uitgaan dat het veld type <tt> T<\/tt> is van type <tt> Nummer<\/tt> of een subtype daarvan.\u00a0 In plaats daarvan het veld type <tt> T<\/tt> kan van elk supertype zijn <tt> Nummer<\/tt> , zoals <tt> Serialiseerbaar<\/tt> of <tt> Voorwerp<\/tt> .\u00a0 Het aanroepen van een methode zoals <tt> intWaarde()<\/tt> is niet langer typeveilig en de compiler zou het moeten afwijzen. Als gevolg hiervan zou de lagere typeparametergrens geen toegang geven tot niet-statische leden die verder gaan dan de leden die in de klasse zijn gedefinieerd <tt> Voorwerp<\/tt> en heeft dus hetzelfde effect als &#8220;no bound&#8221;.<\/p>\n<p><i> Typ Wissen<\/i> .\u00a0 Als we deze logica volgen, heeft het geen zin om het voorkomen van de parameter type te vervangen door de meest linkse ondergrens.\u00a0 Het declareren van een methode zoals de constructor <tt> Doos(<b> T<\/b> T) <\/tt> als constructeur <tt> Doos(<b> Nummer<\/b> T)<\/tt> heeft geen zin, gezien dat <tt> T<\/tt> wordt vervangen door een supertype van <tt> Nummer<\/tt> .\u00a0 Een <tt> Voorwerp<\/tt> kan terecht in een instantiatie aan de constructor worden doorgegeven <tt> Vak&lt;Object&gt;<\/tt> en de constructeur zou het afwijzen.\u00a0 Dit zou volkomen verkeerd zijn.\u00a0\u00a0 Het wissen van het type zou dus alle exemplaren van de typevariabele vervangen<tt> T<\/tt> per type <tt> Voorwerp<\/tt> , en niet volgens de ondergrens ervan.\u00a0 Nogmaals, de ondergrens zou hetzelfde effect hebben als &#8220;geen grens&#8221;.<\/p>\n<p>Wil je erachter komen wat het zou betekenen als beide lager zijn? <i> _En_<\/i> bovengrenzen waren toegestaan?\u00a0\u00a0 Persoonlijk wil ik er niet eens over nadenken en zou ik het liever onder &#8220;niet beheersbaar&#8221; plaatsen, als u dat toestaat.<\/p>\n<p>Het komt erop neer: dat alles is een &#8220;<tt> Geweldig<\/tt> &#8216;bound&#8217; zou je kopen is de beperking waar alleen supertypes van mogen genieten <tt> Nummer<\/tt> kunnen worden gebruikt als typeargumenten.\u00a0 En zelfs dat wordt vaak verkeerd begrepen.\u00a0 Dat zou het NIET betekenen <tt> klasse Box&lt;T super Nummer&gt; {...}<\/tt> bevat alleen exemplaren van supertypes van <tt> Nummer<\/tt> .\u00a0 Integendeel, zoals het onderstaande voorbeeld laat zien!<\/p>\n<p>Voorbeeld (van gebruik van de bovengrens voor een typeparameter bij het wissen van type &#8211; <i> voor<\/i> soort wissen):<\/p>\n<div style=\"margin-left:40px;\">\n<blockquote><p><tt> klasse Box&lt;<b> T supernummer<\/b> &gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 <b> T<\/b> waarde;<\/tt><br \/>\n<tt> \u00a0\u00a0 openbare box(<b> T<\/b> t) { waarde = t; }<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<\/div>\n<p>Voorbeeld (van gebruik van de bovengrens voor een typeparameter bij het wissen van type &#8211; <i> na<\/i> soort wissen):<\/p>\n<div style=\"margin-left:40px;\">\n<blockquote><p><tt> klasse Box {<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 <b> Voorwerp<\/b> waarde;<\/tt><br \/>\n<tt> \u00a0\u00a0 openbare box(<b> Voorwerp<\/b> t) { waarde = t; }<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<\/div>\n<p>A <tt> klasse Box&lt;T <b> Geweldig<\/b> Nummer&gt; {...} <\/tt> zou door typeverwijdering worden vertaald naar a <tt> Doos<\/tt> met daarin een <tt> Voorwerp<\/tt> veld en de constructor ervan zou worden vertaald <tt> Vak(Object t)<\/tt> . Dat is fundamenteel anders dan a <tt> klasse Box&lt;T <b> strekt zich uit<\/b> Nummer&gt; {...}<\/tt> , wat zou worden vertaald naar een <tt> Doos<\/tt> met daarin een <tt> Nummer<\/tt> veld en de constructor ervan zou worden vertaald <tt> Vak(Nummer t)<\/tt> . Bijgevolg is een <tt> Doos&lt;Nummer&gt;<\/tt> ge\u00efnstantieerd uit een<tt> klasse Box&lt;T breidt Nummer&gt; uit {...}<\/tt> zou anders zijn dan a <tt> Doos&lt;Nummer&gt;<\/tt> instantiatie van a <tt> klasse Box&lt;T super Nummer&gt; {...}<\/tt> , wat waarschijnlijk tot verwarring zal leiden.\u00a0 Om deze reden zijn ondergrenzen niet zinvol voor typeparameters van klassen.<\/p>\n<p>&nbsp;<\/p>\n<hr width=\"100%\" \/>\n<p>&nbsp;<\/p>\n<p><b>Ondergrenstypeparameters van methoden<\/b><\/p>\n<p>In combinatie met methoden en hun argumenttypen kan een parameter type met een ondergrens af en toe nuttig zijn.<\/p>\n<p>Voorbeeld (van een methode die baat zou hebben bij een typeparameter met een ondergrens):<\/p>\n<blockquote><p><tt> klasse Paar&lt;X,Y&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 X eerst;<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 Y seconde;<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> \u00a0\u00a0 openbare &lt;<b> Een super-X<\/b> ,<b> B super Y<\/b> &gt; B addToMap(Map&lt;A,B&gt; map) {\/\/ error: type parameter kan geen ondergrens hebben<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 return map.put(eerste, tweede);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> klasse Test {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 public static void main(String[] args) {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Pair&lt;String,Long&gt;-paar = nieuw Pair&lt;&gt;(\"ABC\",42L);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Map&lt;CharSequence, Number&gt; map = HashMap&lt;CharSequence, Number&gt;();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Getalnummer = pair.addToMap(kaart);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>De <tt> toevoegenToMap()<\/tt> methode voegt de inhoud van het paar toe aan een kaart.\u00a0 Elke kaart die supertypes kan bevatten <tt> X<\/tt> En <tt> Y<\/tt> zou doen.\u00a0 De kaart <tt> neerzetten()<\/tt> method retourneert de waarde die in de kaart voor de gegeven sleutel is gevonden, als er al een sleutelwaarde-invoer voor de sleutel in de kaart bestaat.\u00a0 De geretourneerde waarde van de kaart <tt> neerzetten()<\/tt> methode wordt geretourneerd uit de <tt> toevoegenToMap()<\/tt> methode.\u00a0 Onder deze omstandigheden zou men de methode willen declareren zoals hierboven weergegeven: De kaart is geparametriseerd met supertypes van de typeparameters van het paar en de <tt> toevoegenToMap()<\/tt> Het retourtype van de methode is het waardetype van de kaart.<\/p>\n<p>Omdat de compiler geen ondergrenzen voor typeparameters toestaat, hebben we een oplossing nodig.<\/p>\n<p>E\u00e9n oplossing die in je opkomt is het gebruik van een jokerteken, omdat jokertekens een ondergrens kunnen hebben.\u00a0 Hier is een oplossing met behulp van een jokerteken.<\/p>\n<p>Voorbeeld (van een oplossing voor het vorige voorbeeld met behulp van jokertekens):<\/p>\n<blockquote><p><tt> klasse Paar&lt;X,Y&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 X eerst;<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 Y seconde;<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> \u00a0\u00a0 publiek <b> Voorwerp<\/b> addToMap(Map&lt;<b> ? Super X<\/b> , <b> ? super Y<\/b> &gt;-kaart) {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 return map.put(eerste, tweede);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> klasse Test {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 public static void main(String[] args) {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Pair&lt;String,Long&gt;-paar = nieuw Pair&lt;&gt;(\"ABC\",42L);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Map&lt;CharSequence, Number&gt; map = HashMap&lt;CharSequence, Number&gt;();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Nummer nummer = <b> (Nummer)<\/b> pair.addToMap(kaart);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Het werkt, behalve dat er geen manier is om het retourtype naar wens te declareren.\u00a0 Het zou het supertype zijn van <tt> Y<\/tt> die de compiler van het kaarttype opvangt, maar er is geen syntaxis om dit te specificeren.\u00a0 We mogen het retourtype niet declareren als een &#8220;<tt> ? super Y<\/tt> &#8220;, omdat &#8220;<tt> ? super Y<\/tt> &#8221; is een wildcard en geen type en daarom niet toegestaan \u200b\u200bals retourtype. We hebben geen keus en moeten deze gebruiken <tt> Voorwerp<\/tt> in plaats daarvan als het retourtype van onze methode.\u00a0 Dit nogal onspecifieke retourtype dwingt op zijn beurt bellers van de <tt> toevoegenToMap()<\/tt> methode om de retourwaarde naar beneden te gieten <tt> Voorwerp<\/tt> naar zijn werkelijke type.\u00a0 Dit is niet precies wat wij in gedachten hadden.<\/p>\n<p>Een andere oplossing is het gebruik van statische methoden.\u00a0 Hier is een oplossing met een statische in plaats van een niet-statische methode.<\/p>\n<p>Voorbeeld (van een oplossing voor het vorige voorbeeld met behulp van een statische methode):<\/p>\n<blockquote><p><tt> klasse Paar&lt;X,Y&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 X eerst;<\/tt><br \/>\n<tt> \u00a0\u00a0 priv\u00e9 Y seconde;<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> \u00a0\u00a0 publiek <b> statisch<\/b> &lt;<b> A<\/b> ,<b> B<\/b> ,X <b> verlengt A<\/b> ,J <b> verlengt B<\/b> &gt; B addToMap(Pair&lt;X,Y&gt;-paar, Map&lt;<b> A<\/b> ,<b> B<\/b> &gt;-kaart) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 return map.put(paar.eerste,paar.tweede);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> klasse Test {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 public static void main(String[] args) {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Pair&lt;String,Long&gt;-paar = nieuw Pair&lt;&gt;(\"ABC\",42L);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Map&lt;CharSequence, Number&gt; map = HashMap&lt;CharSequence, Number&gt;();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Nummer nummer = <b> Paar<\/b> .addToMap(<b> paar<\/b> ,kaart);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>De generieke <tt> toevoegenToMap()<\/tt> methode heeft vier typeparameters: twee tijdelijke aanduidingen <tt> X<\/tt> En <tt> Y<\/tt> voor het type van het paar en twee tijdelijke aanduidingen <tt> A<\/tt> En <tt> B <\/tt> voor het kaarttype. <tt> A<\/tt> En <tt> B<\/tt> zijn supertypes van <tt> X<\/tt> En <tt> Y<\/tt> , omdat <tt> X<\/tt> En <tt> Y<\/tt> \u00a0 worden verklaard met <tt> A<\/tt> En <tt> B<\/tt> als hun bovengrens. (Merk op dat de typeparameters van de generieke methode <tt> X<\/tt> En <tt> Y<\/tt> hebben er niets mee te maken <tt> Paar<\/tt> klasse <tt> X<\/tt> En <tt> Y<\/tt> parameters.\u00a0 De namen <tt> X<\/tt> En <tt> Y<\/tt> worden hergebruikt voor de generieke methode om ze gemakkelijk herkenbaar te maken als de typeparameters van het paar. Met behulp van vier typeparameters kunnen we het precieze retourtype naar wens declareren: het is hetzelfde type als het waardetype van de kaart.<\/p>\n<p>Voorbeeld (van illegaal gebruik van typeparameter in statische context van een generieke klasse):<\/p>\n<blockquote><p><tt> klasse SommigeKlasse<b> <span style=\"color:#000099;\"> &lt;T&gt;<\/span> <\/b> {<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> statische initialisator, statisch veld, statische methode<\/i><br \/>\n<tt> \u00a0 <b> statisch<\/b> {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 SommigeKlasse&lt;<b> <span style=\"color:#000099;\"> T<\/span> <\/b> &gt;-test = nieuwe SomeClass&lt;<b> <span style=\"color:#000099;\"> T<\/span> <\/b> &gt;(); <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 <b> statisch<\/b> <b> <span style=\"color:#000099;\"> T<\/span> <\/b> globalInfo;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 publiek\u00a0 <b> statisch<\/b> <b> <span style=\"color:#000099;\"> T <\/span> <\/b> getGlobalInfo() {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 retourneer globalInfo;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> niet-statische initialisator, niet-statisch veld, niet-statische methode<\/i><br \/>\n<tt> \u00a0 {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 SommigeKlasse&lt;<b> <span style=\"color:#000099;\"> T<\/span> <\/b> &gt;-test = nieuwe SomeClass&lt;<b> <span style=\"color:#000099;\"> T<\/span> <\/b> &gt;();<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 priv\u00e9\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#000099;\"> T<\/span> <\/b> lokaleInfo;<\/tt><br \/>\n<tt> \u00a0 publiek\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#000099;\"> T<\/span> <\/b> getLocalInfo() {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 lokaleInfo retourneren;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> statische geneste typen<\/i><br \/>\n<tt> \u00a0 publiek <b> statisch<\/b> <b> klas<\/b> Mislukking verlengt uitzondering {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 besloten finale <b> <span style=\"color:#000099;\"> T<\/span> <\/b> informatie;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 openbare mislukking(<b> <span style=\"color:#000099;\"> T<\/span> <\/b> t) {info = t; }\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 publiek <b> <span style=\"color:#000099;\"> T<\/span> <\/b> getInfo() {retourinfo; }\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 <b> interface<\/b> Kopieerbaar {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 <b> <span style=\"color:#000099;\"> T<\/span> <\/b> kopi\u00ebren();\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 <b> opsomming<\/b> Staat {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 GELDIG, ONGELDIG;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 priv\u00e9 <b> <span style=\"color:#000099;\"> T<\/span> <\/b> informatie; \/\/ fout<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 openbare ongeldige setInfo(<b> <span style=\"color:#000099;\"> T<\/span> <\/b> t) {info = t; } <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 publiek <b> <span style=\"color:#000099;\"> T<\/span> <\/b> getInfo() {retourinfo; }\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> niet-statische geneste typen<\/i><br \/>\n<tt> \u00a0 publiek <b> klas<\/b> Accessoire {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 publiek <b> <span style=\"color:#000099;\"> T<\/span> <\/b> getInfo() { return localInfo; }<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Het voorbeeld illustreert dat de parameter type niet kan worden gebruikt in de statische context van een generieke klasse.\u00a0 Het laat ook zien dat geneste interfaces en enum-typen worden beschouwd als statische typeleden van de klasse.\u00a0 Alleen binnenklassen, dat wil zeggen niet-statische geneste klassen, kunnen de parameter type van de omsluitende generieke klasse gebruiken.<\/p>\n<p>Het bereik van de parameter type van een interface is de volledige definitie van de interface, met uitzondering van eventuele velden of geneste typen.\u00a0 Dit komt omdat velden en geneste typen die in een interface zijn gedefinieerd impliciet statisch zijn.<\/p>\n<p>Voorbeeld (van illegaal gebruik van parameter type in een generieke interface):<\/p>\n<blockquote><p><tt> interface SommigeInterface<b> <span style=\"color:#000099;\"> &lt;T&gt;<\/span> <\/b> {<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> veld<\/i><br \/>\n<tt> \u00a0 SommigeKlasse&lt;<b> <span style=\"color:#000099;\"> T<\/span> <\/b> &gt;-waarde = nieuwe SomeClass&lt;<b> <span style=\"color:#000099;\"> T<\/span> <\/b> &gt;();\u00a0 <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> geneste soort<\/i><br \/>\n<tt> \u00a0 <b> klas<\/b> Accessoire {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 publiek <b> <span style=\"color:#000099;\"> T <\/span> <\/b> getInfo() {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ fout<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 retourwaarde.getGlobalInfo();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> methoden<\/i><br \/>\n<tt> \u00a0 <b> <span style=\"color:#000099;\"> T<\/span> <\/b> getWaarde();<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Het voorbeeld laat zien dat velden van een interface impliciet statisch zijn, zodat de parameter type nergens kan worden gebruikt bij de declaratie van een veld van een generieke interface.\u00a0 Op dezelfde manier wordt de geneste klasse beschouwd als een statische geneste klasse, niet als een binnenklasse, en om deze reden is het gebruik van de parameter type waar dan ook in de geneste klasse illegaal.<\/p>\n<p><b> <i> Oplossing voor geneste statische klassen en interfaces:<\/i> <\/b><\/p>\n<p>Bij statisch geneste klassen en interfaces is dit geen grote ramp.\u00a0 Als tijdelijke oplossing kunnen we de statische klasse of interface zelf genereren.<\/p>\n<p>Voorbeeld (oplossing: genereer het geneste statische type):<\/p>\n<blockquote><p><tt> klasse Wrapper<b> <span style=\"color:#000099;\"> &lt;T&gt;<\/span> <\/b> {<\/tt><br \/>\n<tt> \u00a0 besloten finale <b> <span style=\"color:#000099;\"> T<\/span> <\/b> hetObject;<\/tt><\/p><\/blockquote>\n<blockquote><p><tt> \u00a0 openbare verpakking(<b> <span style=\"color:#000099;\"> T<\/span> <\/b> t) { hetObject = t; }<\/tt><br \/>\n<tt> \u00a0 publiek <b> <span style=\"color:#000099;\"> T<\/span> <\/b> getWrapper() { return theObject; }<\/tt><tt> \u00a0 publiek Onveranderlijk<b> &lt;T&gt;<\/b> maak onveranderlijk() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 retourneer nieuw Onveranderlijk<b> &lt;T&gt;<\/b> (hetObject);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 publiek Veranderlijk<b> &lt;T&gt;<\/b> makeMutable() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 retourneer nieuw veranderlijk<b> &lt;T&gt;<\/b> (hetObject);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 statisch &lt;A&gt; A makeClone(A theObject) { ... }<\/tt><\/p>\n<p><tt> \u00a0 openbare statische laatste klasse Onveranderlijk<b> &lt;A&gt;<\/b> { <b> \/\/ is nu een generieke klasse<\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 besloten finale <b> A<\/b> hetObject;<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 openbaar Onveranderlijk(<b> A<\/b> arg) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 hetObject = makeClone(arg);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 publiek <b> A<\/b> getWrappedItem() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return makeClone(hetObject);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 openbare statische klasse Muteerbaar<b> &lt;A&gt;<\/b> {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ... vergelijkbaar ...<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Er bestaat geen dergelijke oplossing voor geneste enum-typen, omdat deze niet generiek kunnen zijn.<\/p>\n<p><b> <i> Oplossing voor geneste statische klassen:<\/i> <\/b><\/p>\n<p>Als het geneste statische type een klasse is, zou een alternatieve oplossing erin bestaan \u200b\u200bde statische klasse in een niet-statische binnenklasse te veranderen.<\/p>\n<p>Voorbeeld (oplossing: gebruik een innerlijke klasse):<\/p>\n<blockquote><p><tt> klasse Wrapper<b> <span style=\"color:#000099;\"> &lt;T&gt;<\/span> <\/b> {<\/tt><br \/>\n<tt> \u00a0 besloten finale <b> <span style=\"color:#000099;\"> T<\/span> <\/b> hetObject;<\/tt><\/p><\/blockquote>\n<blockquote><p><tt> \u00a0 openbare verpakking(<b> <span style=\"color:#000099;\"> T<\/span> <\/b> t) { hetObject = t; }<\/tt><br \/>\n<tt> \u00a0 publiek <b> <span style=\"color:#000099;\"> T<\/span> <\/b> getWrapper() { return theObject; }<\/tt><tt> \u00a0 public veranderlijk makeMutable() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 opbrengst <b> dit.<\/b> nieuw Mutable(hetObject);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 public Onveranderlijk makeImmutable() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 opbrengst <b> dit.<\/b> nieuw onveranderlijk(hetObject);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 statisch &lt;A&gt; A makeClone(A theObject) { ... }<\/tt><\/p>\n<p><tt> \u00a0 openbare eindklasse Onveranderlijk {\u00a0 <b> \/\/ is niet langer een statische klasse<\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 besloten finale <b> T<\/b> hetObject;<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0\u00a0\u00a0 openbaar Onveranderlijk(<b> T<\/b> arg) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 hetObject = makeClone(arg);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 publiek <b> T<\/b> getWrappedItem() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return makeClone(hetObject);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 openbare klasse Veranderlijk\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ... vergelijkbaar ...<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Deze oplossing brengt een bepaalde hoeveelheid overhead met zich mee, omdat alle innerlijke klassen een verborgen verwijzing hebben naar een exemplaar van het buitenste type, waar ze in dit voorbeeld geen behoefte aan hebben en er ook geen voordeel uit halen; de verborgen referentie is slechts bagage.\u00a0 Vaak worden innerlijke klassen gecombineerd met interfaces om de innerlijke klasse een priv\u00e9-implementatiedetail van de omsluitende klasse te houden.\u00a0 Hetzelfde kunnen wij hier doen.<\/p>\n<p>Voorbeeld (de vorige oplossing verfijnd):<\/p>\n<blockquote><p><tt> klasse Wrapper<b> <span style=\"color:#000099;\"> &lt;T&gt;<\/span> <\/b> {<\/tt><br \/>\n<tt> \u00a0 besloten finale <b> <span style=\"color:#000099;\"> T<\/span> <\/b> hetObject;<\/tt><\/p><\/blockquote>\n<blockquote><p><tt> \u00a0 openbare verpakking(<b> <span style=\"color:#000099;\"> T<\/span> <\/b> t) { hetObject = t; }<\/tt><br \/>\n<tt> \u00a0 publiek <b> <span style=\"color:#000099;\"> T<\/span> <\/b> getWrapper() { return theObject; }<\/tt><tt> \u00a0 publiek Veranderlijk<b> &lt;T&gt;<\/b> makeMutable() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 return this.new Mutable(theObject);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 publiek Onveranderlijk<b> &lt;T&gt;<\/b> maak onveranderlijk() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 return this.new Onveranderlijk (hetObject);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 priv\u00e9 statisch &lt;A&gt; A makeClone(A theObject) { ... }<\/tt><\/p>\n<p><tt> \u00a0 <b> publieke interface <\/b> Onveranderlijk&lt;S&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 S getWrappedItem();<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 <b> publieke interface <\/b> Veranderlijk&lt;S&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 S getWrappedItem();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 void setWrappedItem(S arg);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 <b> priv\u00e9<\/b> laatste les Onveranderlijke Implementatie <b> implementeert onveranderlijk&lt;T&gt;<\/b> {\u00a0<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0\u00a0\u00a0 priv\u00e9 finale T theObject;<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0\u00a0\u00a0 public ImmutableImplementation(T arg) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 hetObject = makeClone(arg);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 openbare T getWrappedItem() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return makeClone(hetObject);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 <b> priv\u00e9<\/b> klasse MutableImplementatie <b> implementeert Mutable&lt;T&gt;<\/b> {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ... vergelijkbaar ...<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Zoals u kunt zien, moeten de geneste openbare interfaces generiek zijn, terwijl de binnenste priv\u00e9klassen de parameter type van de omsluitende klasse kunnen gebruiken.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<table width=\"100%\" cellpadding=\"10\">\n<tbody>\n<tr valign=\"TOP\">\n<td colspan=\"2\" width=\"68%\"><b>\u00a0<\/b><\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\"><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Raadpleeg deze veelgestelde vraag voor meer informatie: <a href=\"http:\/\/www.angelikalanger.com\/GenericsFAQ\/JavaGenericsFAQ.html#SECTION1\" rel=\"nofollow\">http:\/\/www.angelikalanger.com\/GenericsFAQ\/JavaGenericsFAQ.html#SECTION1<\/a> Hier volgen enkele belangrijke punten uit deze FAQ. Voorbeeld (van een generiek type): klasse Paar&lt;X,Y&gt; {\u00a0 \u00a0 priv\u00e9 X eerst; \u00a0 priv\u00e9 Y seconde; \u00a0 publiek paar(X a1, Y a2) { \u00a0\u00a0\u00a0 eerste = a1; \u00a0\u00a0\u00a0 twee = a2; \u00a0 } \u00a0 openbare X getFirst() [&hellip;]<\/p>\n","protected":false},"author":65283547,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_wpcom_ai_launchpad_first_post":false,"_jetpack_hide_featured_image":false,"_jetpack_featured_image_duplicate_dismissed":0,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Generics in short form","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[1017],"tags":[18369,2549795,6280762],"class_list":["post-31","post","type-post","status-publish","format-standard","hentry","category-java","tag-generics","tag-java-2","tag-java-generics"],"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4CoHV-v","jetpack-related-posts":[],"jetpack_likes_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/posts\/31","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/users\/65283547"}],"replies":[{"embeddable":true,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/comments?post=31"}],"version-history":[{"count":8,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/posts\/31\/revisions"}],"predecessor-version":[{"id":42,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/posts\/31\/revisions\/42"}],"wp:attachment":[{"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/media?parent=31"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/categories?post=31"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/tags?post=31"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}