Ohjelmointi

Java 101: Oleellisen Java-kielen ominaisuuksien esittely, osa 5

Edellinen 1 2 Sivu 2 Sivu 2/2

Tyyppien päättely ja yleiset konstruktorit yleisille ja ei-yleisille luokille

Geneeriset ja ei-yleiset luokat voivat ilmoittaa yleiset konstruktorit, joissa konstruktorilla on muodollinen tyyppiparametriluettelo. Voit esimerkiksi ilmoittaa seuraavan yleisluokan yleisen konstruktorin kanssa:

 julkisen luokan laatikko {julkinen laatikko (T t) {// ...}} 

Tässä ilmoituksessa määritetään yleinen luokka Laatikko muodollisen tyypin parametrilla E. Se määrittää myös yleisen konstruktorin, jolla on muodollinen tyypin parametri T. Voit ilmentää yleisluokan ja kutsua sen rakentajan seuraavasti:

 uusi laatikko ("Aggies") 

Tämä lauseke luo Laatikko, ohimennen Marmori että E. Myös kääntäjä päättelee Merkkijono kuten Ttodellinen tyyppiargumentti, koska rakentajan argumentti on a Merkkijono esine.

Pre-Java 7-kääntäjät päättelevät yleisen konstruktorin todelliset tyypin argumentit samalla tavalla kuin yleisen menetelmän argumentit. Java 7: n kääntäjä voi kuitenkin päätellä timanttioperaattorikontekstissa ilmentyvien geneeristen luokkien todelliset tyyppiargumentit. Harkitse seuraavaa esimerkkiä:

 Box box = uusi laatikko ("Aggies"); 

Sekä päätellä tyyppi Marmori muodollisen tyypin parametrille E luokkaan Laatikko, kääntäjä päättelee tyypin Merkkijono muodollisen tyypin parametrille T tämän geneerisen luokan konstruktorista.

Projektikolikon pieni muutos # 8: Yksinkertaistettu varargs-menetelmän kutsuminen

Ennen Java 7: ää kukin yritys kutsua varargs (muuttujan argumentit, joka tunnetaan myös nimellä vaihteleva arity) -menetelmä, jonka varargs-tyyppi ei ole vahvistettavissa, sai kääntäjän lähettämään "vaarallisen toiminnan" varoituksen. Poistaaksesi samanlaisten varoitusviestien mahdollisuuden (yksi kutakin sivustoa kohden), Java 7 siirsi varoituksen puhelusivustolta menetelmäilmoitukseen.

Korjattavat ja toistamattomat tyypit

A uusittavissa oleva tyyppi paljastaa täydelliset tyyppitietonsa ajon aikana. Esimerkkejä ovat primitiiviset tyypit, ei-geneeriset tyypit, raakatyypit ja sitoutumattomien yleismerkkien kutsut. Sen sijaan a ei uudelleenvahvistettava tyyppi on poistanut tyyppitiedot kokoamisajankohtana tyypin poiston perusteella, jotta varmistetaan binaarinen yhteensopivuus ennen kirjaimia luotujen Java-kirjastojen ja sovellusten kanssa. Esimerkkejä ovat Aseta ja Aseta. Koska uudelleenvahvistamaton tyyppi ei ole täysin käytettävissä ajon aikana, JVM ei pysty erottamaan toisistaan Aseta ja Aseta; ajon aikana vain raakatyyppi Aseta on käytettävissä.

Vararg-syöttöparametreja sisältävät yleiset menetelmät voivat aiheuttaa kasan saastuminen, jossa parametrisoidun tyypin muuttuja viittaa objektiin, joka ei ole kyseistä parametrisoitua tyyppiä (esimerkiksi jos raakatyyppi on sekoitettu parametrisoituun tyyppiin). Kääntäjä ilmoittaa "tarkistamattoman varoituksen", koska parametrisoituun tyyppiin (kuten cast- tai method-kutsuun) liittyvän toiminnan oikeellisuutta ei voida tarkistaa.

Listaus 13 osoittaa kasan pilaantumista ei-varargs-kontekstissa.

Listaus 13. Kasan pilaantumisen osoittaminen muussa kuin varargs-kontekstissa

 tuoda java.util.Iterator; tuo java.util.Set; tuo java.util.TreeSet; public class HeapPollutionDemo {public static void main (String [] args) {Set s = new TreeSet (); Aseta ss = s; // tarkistamaton varoitus s.add (uusi kokonaisluku (42)); // toinen tarkistamaton varoitus Iterator iter = ss.iterator (); while (iter.hasNext ()) {Merkkijono str = iter.next (); // ClassCastException heitetty System.out.println (str); }}} 

Vaihteleva ss on parametrisoitu tyyppi Aseta. Kun java.util.Set johon viitataan s on osoitettu ss, kääntäjä luo tarkistamattoman varoituksen. Se tekee niin, koska kääntäjä ei voi määrittää sitä s viittaa a Aseta tyyppi (ei). Tuloksena on kasan saastuminen. (Kääntäjä sallii tämän tehtävän säilyttää taaksepäin yhteensopivuuden vanhojen Java-versioiden kanssa, jotka eivät tue geneerisiä tiedostoja. Aseta osaksi Aseta, mikä johtaa yhteen Aseta nimitetään toiselle Aseta.)

Kääntäjä luo toisen tarkistamattoman varoituksen kutsuvalle linjalle Asetaon lisätä() menetelmä. Se tekee niin, koska se ei voi määrittää, onko muuttuja s viittaa a Aseta tai Aseta tyyppi. Tämä on toinen kasan pilaantumistilanne. (Kääntäjä sallii tämän menetelmän kutsun, koska poisto muuttuu Asetaon looginen lisäys (E e) menetelmä looginen lisäys (Object o), joka voi lisätä joukkoon kaikenlaisia ​​esineitä, mukaan lukien java.lang.I kokonaisluku alatyyppi java.lang.objekti.)

Kasan pilaantumista voi helposti esiintyä varargs-tilanteessa. Harkitse esimerkiksi Listing 14.

Listaus 14. Kasan pilaantumisen osoittaminen varargs-kontekstissa

 tuo java.util.Arrays; tuo java.util.List; public class UnsafeVarargsDemo {public static void main (String [] args) {unsafe (Arrays.asList ("A", "B", "C"), Arrays.asList ("D", "E", "F") ); } staattinen tyhjä vaarallinen (Lista ... l) {Objekti [] oArray = l; oArray [0] = Arrays.asList (uusi kaksinkertainen (3.5)); Merkkijono s = l [0] .get (0); }} 

Objekti [] oArray = l; Tehtävä tuo mahdollisuuden kasaan. Arvo, joka ei vastaa varargs-parametrin parametrisoitua tyyppiä l voidaan määrittää muuttujalle oArray. Kääntäjä ei kuitenkaan luo tarkistamatonta varoitusta, koska se on jo tehnyt niin käännettäessä Luettelo ... l että Luettelo [] l. Tämä tehtävä on kelvollinen, koska muuttuja l on tyyppi Lista[], mitkä alatyypit Esine[].

Kääntäjä ei myöskään anna varoitusta tai virhettä määrittäessään Lista minkä tahansa tyyppinen esine mille tahansa oArraymatriisin komponentit; esimerkiksi, oArray [0] = Arrays.asList (uusi kaksinkertainen (3.5));. Tämä tehtävä osoitetaan ensimmäisen ryhmän matriisikomponentille oArray a Lista esine, joka sisältää yhden java.lang.Tupla esine.

Merkkijono s = l [0] .get (0); tehtävä on ongelmallista. Muuttujan ensimmäiseen matriisikomponenttiin tallennettu objekti l on tyyppi Lista, mutta tämä tehtävä odottaa tyypin objektia Lista. Tämän seurauksena JVM heittää java.lang.ClassCastException.

Käännä tämä lähdekoodi (javac -Xlint: tarkistamaton UnsafeVarargsDemo.java). Noudata seuraavaa lähtöä (muotoiltu hieman luettavuuden vuoksi), kun se on koottu Java SE 7 -päivityksen 6 alla:

 UnsafeVarargsDemo.java:8: varoitus: [ei tarkastettu] tarkistamaton yleinen taulukon luonti Varargs-parametrin tyypille List [] vaarallinen (Arrays.asList ("A", "B", "C"), ^ UnsafeVarargsDemo.java:12: varoitus : [ei tarkastettu] Mahdollinen kasan pilaantuminen parametrisoidusta vararg-tyypistä List static void unsafe (List ... l) ^ 2 varoitusta 

Java 101: n johdannossa geneerisiin tuotteisiin totesin, että et voi käyttää tyypin parametreja taulukon luomislausekkeissa. Et voi esimerkiksi määrittää elementit = uusi E [koko];. Kääntäjä ilmoittaa "yleinen taulukon luomisvirhe" -viestin, kun yrität tehdä niin. On kuitenkin edelleen mahdollista luoda yleinen taulukko, mutta vain varargs-kontekstissa, ja tämä on ensimmäinen varoitusviesti. Kulissien takana kääntäjä muuttuu Luettelo ... l että Luettelo [] l ja sitten Luettelo [] l.

Huomaa, että kasan pilaantumisvaroitus syntyy vaarallinen () menetelmän ilmoitussivusto. Tätä viestiä ei luoda tämän menetelmän soittosivustolla, kuten Java 5- ja 6-kääntäjät.

Kaikki varargs-menetelmät eivät edistä kasan pilaantumista. Varoitusviesti kuitenkin lähetetään menetelmän ilmoitussivustolla. Jos tiedät, että menetelmäsi ei edistä kasan saastumista, voit estää tämän varoituksen ilmoittamalla siitä @SafeVarargs huomautus - Java 7 esitteli java.lang.SafeVarargs merkinnän tyyppi. Esimerkiksi, koska ei ole mitään keinoa Taulukot luokan asList () menetelmällä kasan pilaantumisen edistämiseksi, tämän menetelmän ilmoitukseen on liitetty merkintä @SafeVarargs, seuraavasti:

 @SafeVarargs public static List asList (T ... a) 

@SafeVarargs merkintä eliminoi yleisen taulukon luomisen ja kasan pilaantumista koskevat varoitusviestit. Se on dokumentoitu osa menetelmän sopimusta ja väittää, että menetelmän toteutus ei käsittele varargsin muodollista parametria väärin.

Tiivistettynä

Java 7 paransi kehittäjien tuottavuutta ottamalla käyttöön automaattisen resurssienhallinnan resursseja kokeilemalla -lausekkeen kautta uuden kanssa Automaattisesti suljettava käyttöliittymä, merkkijono, monisäiliö, viimeinen uudelleenveto, binaariset literaalit, alleviivat numerolitraaleissa, muutokset kääntäjän tyypin päättelyalgoritmiin, joka otti käyttöön ns. timanttioperaattorin, ja yksinkertaistetun varargs-menetelmän kutsun. Seuraavaksi Java 101: Seuraava sukupolvi -sarja on katsaus Java 8: n lambda- ja toiminnallisten käyttöliittymien kieliominaisuuksiin.

Tämän tarinan "Java 101: Essential Java language features tour, Part 5" julkaisi alun perin JavaWorld.