Naujokai „Java“ kalboje dažnai patiria painiavą. Jų suglumimą daugiausia lemia „Java“ egzotinių kalbos ypatybių, tokių kaip generiniai vaistai ir lambdas, paletė. Tačiau net ir paprastesnės funkcijos, tokios kaip sąsajos, gali sukelti painiavos.
Neseniai susidūriau su klausimu, kodėl „Java“ palaiko sąsajas (per sąsaja
ir padargai
raktiniai žodžiai). Kai aš pradėjau mokytis „Java“ 1990-aisiais, į šį klausimą dažnai buvo atsakyta teigiant, kad sąsajos apeina „Java“ nepakankamą palaikymą daugkartinis įgyvendinimo paveldėjimas (vaikų klasės paveldimos iš kelių tėvų klasių). Tačiau sąsajos tarnauja kur kas labiau nei kludge. Šiame įraše pateikiu šešis vaidmenis, kuriuos sąsajos atlieka „Java“ kalba.
Apie daugkartinį paveldėjimą
Terminas daugkartinis paveldėjimas paprastai vartojamas kalbant apie vaikų klasę, paveldinčią iš kelių tėvų klasių. Java kalboje terminas daugkartinis įgyvendinimo paveldėjimas reiškia tą patį. „Java“ taip pat palaiko kelių sąsajų paveldėjimas kurioje vaiko sąsaja gali paveldėti iš kelių tėvų sąsajų. Norėdami sužinoti daugiau apie daugkartinį paveldėjimą (įskaitant garsiąją deimantų problemą), peržiūrėkite Vikipedijos įrašą „Kelių paveldėjimas“.
1 vaidmuo: anotacijų tipų deklaravimas
sąsaja
raktinis žodis yra perkrautas naudoti deklaruojant anotacijų tipus. Pavyzdžiui, 1 sąraše pateikiama paprasta Stubas
anotacijos tipas.
1 sąrašas. Stub.java
importuoti java.lang.annotation.Retention; importuoti java.lang.annotation.RetentionPolicy; @Retention (RetentionPolicy.RUNTIME) public @interface Stub {int id (); // Kabliataškis nutraukia elemento deklaraciją. String dueDate (); Eilučių kūrėjas () numatytasis „nepriskirtas“; }
Stubas
apibūdina kategoriją anotacijos (anotacijos tipo egzemplioriai), žymintys nebaigtus tipus ir metodus. Jo deklaracija prasideda antrašte, susidedančioje iš @
po jo sąsaja
raktinis žodis, po jo pavadinimas.
Šis anotacijos tipas skelbia tris elementai, kurį galite laikyti metodo antraštėmis:
ID ()
pateikia sveiku skaičiumi pagrįstą šaknies identifikatoriųdueDate ()
nurodo datą, iki kurios šaknis turi būti užpildytas koduprogramuotojas()
identifikuoja kūrėją, atsakingą už šnipinėjimo užpildymą
Elementas grąžina bet kokią reikšmę, kurią jam suteikia anotacija. Jei elementas nenurodytas, jo numatytoji vertė (vadovaujantis numatytas
deklaracijos raktinis žodis) grąžinama.
2 sąrašas rodo Stubas
nebaigto kontekste KontaktaiMgr
klasė; klasė ir jos vienišas metodas buvo pažymėti @Stub
anotacijos.
2 sąrašas. KontaktaiMgr.java
@Stub (id = 1, dueDate = "2016-12-31") public class ContactMgr {@Stub (id = 2, dueDate = "2016-06-31", developer = "Marty") public void addContact (String contactID ) {}}
Anotacijos tipo egzempliorius prasideda @
, po kurio yra anotacijos tipo pavadinimas. Čia, pirmasis @Stub
anotacija identifikuoja save kaip numerį 1, kurio mokėjimo data yra 2016 m. gruodžio 31 d. Kūrėjas, atsakingas už įrašo užpildymą, dar nebuvo priskirtas. Priešingai, antrasis @Stub
anotacija identifikuoja save kaip 2 numerį, kurio terminas yra 2016 m. birželio 31 d. Už kūrinio užpildymą atsakingas kūrėjas yra Marty.
Anotacijos turi būti apdorotos, kad būtų bet kokios naudos. (Stubas
yra anotuotas @Retention (RetentionPolicy.RUNTIME)
kad jį būtų galima apdoroti.) 3 sąraše pateikiama a „StubFinder“
programa, kuri praneša apie klasės @Stub
anotacijos.
3 sąrašas. StubFinder.java
importuoti java.lang.reflect.Method; public class StubFinder {public static void main (String [] args) meta išimtį {if (args.length! = 1) {System.err.println ("naudojimas: java StubFinder classfile"); grįžti; } Class clazz = Class.forName (argumentai [0]); if (clazz.isAnnotationPresent (Tūbų klasė)) {Stub stub = clazz.getAnnotation (Tūbų klasė); System.out.println ("Įrašo ID =" + stub.id ()); System.out.println ("Įrašymo data =" + stub.dueDate ()); System.out.println ("Stub Developer =" + stub.developer ()); System.out.println (); } Metodas [] metodai = clazz.getMethods (); for (int i = 0; i <metodų.ilgis; i ++) if (metodai [i] .isAnnotationPresent („Stub.class“)) {Stub stub = metodai [i] .getAnnotation (Stub.class); System.out.println ("Įrašo ID =" + stub.id ()); System.out.println ("Įrašymo data =" + stub.dueDate ()); System.out.println ("Stub Developer =" + stub.developer ()); System.out.println (); }}}
3 sąrašas pagrindinis ()
metodas naudoja „Java Reflection“ API, kad gautų visus @Stub
anotacijos, prieš kurias įrašoma klasės deklaracija, taip pat jos metodo deklaracijos.
Sudarykite 1–3 sąrašus taip:
javac * .java
Paleiskite gautą programą taip:
java StubFinder KontaktaiMgr
Turėtumėte stebėti šį rezultatą:
Rūšio ID = 1 Tikrinimo data = 2016 12 31 Duomenų kūrėjas = nepriskirtas Žodžio ID = 2 Tikrinimo data = 2016 06 31 Stub kūrėjas = Marty
Galite teigti, kad anotacijų tipai ir jų anotacijos neturi nieko bendra su sąsajomis. Juk klasės deklaracijos ir padargai
raktinio žodžio nėra. Tačiau nesutikčiau su šia išvada.
@interface
yra panašus į klasė
tuo jis įveda tipą. Jos elementai yra metodai, kurie yra įgyvendinami (užkulisiuose) siekiant grąžinti vertybes. Elementai su numatytas
reikšmės grąžina vertes, net jei jų nėra anotacijose, kurios yra panašios į objektus. Nenumatytieji elementai visada turi būti anotacijoje ir turi būti deklaruoti, kad būtų grąžinta vertė. Todėl tarsi klasė buvo paskelbta ir kad klasė įgyvendina sąsajos metodus.
2 vaidmuo: nuo įgyvendinimo nepriklausomų galimybių aprašymas
Skirtingos klasės gali pasiūlyti bendras galimybes. Pavyzdžiui, java.nio.CharBuffer
, javax.swing.text.Segment
, java.lang.Stringas
, java.lang.StringBuffer
ir java.lang.StringBuilder
klasės suteikia prieigą prie skaitomų sekų char
vertybes.
Kai klasės siūlo bendrą galimybę, šios galimybės sąsają galima išgauti pakartotiniam naudojimui. Pavyzdžiui, sąsaja su „skaitoma seka char
vertės "gebėjimas buvo išgautas į java.lang.CharSequence
sąsaja. CharSequence
suteikia vienodą, tik skaitomą prieigą prie daugybės skirtingų tipų char
sekos.
Tarkime, kad jūsų paprašė parašyti nedidelę programą, kurioje būtų skaičiuojamas kiekvienos rūšies mažųjų raidžių atvejų skaičius CharBuffer
, Stygos
ir „StringBuffer“
objektai. Gerai pagalvoję, galite sugalvoti 4 sąrašą. (Aš paprastai vengčiau kultūriškai šališkų posakių, tokių kaip ch - „a“
, bet noriu, kad pavyzdys būtų paprastas.)
4 sąrašas. Freq.java
(1 versija)
importuoti java.nio.CharBuffer; public class Freq {public static void main (String [] args) {if (args.length! = 1) {System.err.println ("naudojimas: java Freq tekstas"); grįžti; } analizuotiS (argumentai [0]); analizuotiSB (naujas „StringBuffer“ (argumentai [0])); analizuotiCB (CharBuffer.wrap (argumentai [0])); } static void analizuotiCB (CharBuffer cb) {int count [] = new int [26]; o (cb.hasRemaining ()) {char ch = cb.get (); jei (ch> = 'a' && ch <= 'z') skaičiuojama [ch - 'a'] ++; } for (int i = 0; i <count.length; i ++) System.out.printf ("% c skaičius yra% d% n", (i + 'a'), skaičiuojamas [i]); System.out.println (); } static void analysisS (String s) {int count [] = new int [26]; nes (int i = 0; i = 'a' && ch <= 'z') skaičiuojama [ch - 'a'] ++; } for (int i = 0; i <count.length; i ++) System.out.printf ("% c skaičius yra% d% n", (i + 'a'), skaičiuojamas [i]); System.out.println (); } static void analizuotiSB (StringBuffer sb) {int skaičius [] = naujas int [26]; nes (int i = 0; i = 'a' && ch <= 'z') skaičiuojama [ch - 'a'] ++; } for (int i = 0; i <count.length; i ++) System.out.printf ("% c skaičius yra% d% n", (i + 'a'), skaičiuojamas [i]); System.out.println (); }}
4 sąraše pateikiami trys skirtingi analizuoti
mažųjų raidžių atvejų skaičiaus registravimo ir šios statistikos pateikimo metodai. nors Stygos
ir „StringBuffer“
variantai yra praktiškai identiški (ir jums gali kilti pagunda sukurti vieną metodą abiem), CharBuffer
variantas skiriasi žymiai.
4 sąrašas rodo daugybę pasikartojančių kodų, todėl gaunama didesnė klasės byla, nei būtina. Tą patį statistinį tikslą galite pasiekti dirbdami su CharSequence
sąsaja. 5 sąraše pateikiama alternatyvi dažnio programos versija, kuria remiamasi CharSequence
.
5 sąrašas. Freq.java
(2 versija)
importuoti java.nio.CharBuffer; public class Freq {public static void main (String [] args) {if (args.length! = 1) {System.err.println ("naudojimas: java Freq tekstas"); grįžti; } analizuoti (argumentai [0]); analizuoti (naujas „StringBuffer“ (argumentai [0])); analizuoti (CharBuffer.wrap (args [0])); } static void analizė (CharSequence cs) {int skaičius [] = naujas int [26]; nes (int i = 0; i = 'a' && ch <= 'z') skaičiuojama [ch - 'a'] ++; } for (int i = 0; i <count.length; i ++) System.out.printf ("% c skaičius yra% d% n", (i + 'a'), skaičiuojamas [i]); System.out.println (); }}
5 sąrašas atskleidžia daug paprastesnę programą, kurią lemia kodavimas analizuoti ()
gauti a CharSequence
argumentas. Nes kiekvienas iš Stygos
, „StringBuffer“
ir CharBuffer
padargai CharSequence
, teisėta perduoti tokio tipo egzempliorius analizuoti ()
.
Kitas pavyzdys
Išraiška CharBuffer.wrap (argumentai [0])
yra dar vienas a išlaikymo pavyzdys Stygos
prieštarauti tipo parametrui CharSequence
.
Apibendrinant galima pasakyti, kad antrasis sąsajos vaidmuo yra apibūdinti nuo įgyvendinimo nepriklausomas galimybes. Koduodami sąsają (pvz., CharSequence
), o ne į klasę (pvz., Stygos
, „StringBuffer“
arba CharBuffer
), vengsite pasikartojančio kodo ir generuosite mažesnes klasės bylas. Šiuo atveju aš pasiekiau sumažėjimą daugiau nei 50%.
3 vaidmuo: bibliotekos evoliucijos palengvinimas
„Java 8“ supažindino mus su itin naudinga „lambda“ kalbos funkcija ir „Streams“ API (daugiausia dėmesio skiriant tam, koks skaičiavimas turėtų būti atliekamas, o ne kaip tai turėtų būti atliekama). „Lambdas“ ir „Srautai“ leidžia kūrėjams daug lengviau įdiegti lygiagretumą savo programose. Deja, „Java Collections Framework“ negalėjo pasinaudoti šiomis galimybėmis, nereikalaujant didelio perrašymo.
Norėdami greitai patobulinti kolekcijas, skirtas naudoti kaip srauto šaltinius ir paskirties vietas, palaikykite numatytieji metodai (taip pat žinomas kaip pratęsimo metodai), kurie yra ne statiniai metodai, kurių antraštėse yra prieš numatytas
raktinis žodis ir tiekimo kodo turinys buvo pridėtas prie „Java“ sąsajos funkcijos. Numatytieji metodai priklauso sąsajoms; jų neįgyvendina (bet gali nepaisyti) klasės, diegiančios sąsajas. Be to, juos galima iškviesti naudojant objektų nuorodas.
Kai numatytieji metodai tapo kalbos dalimi, šie metodai buvo pridėti prie java.util.Rinkimas
sąsaja, suteikianti tiltą tarp kolekcijų ir srautų:
numatytasis srautas parallelStream ()
: Grąžinkite (galbūt) lygiagretęjava.util.stream.Stream
objektas, kurio šaltinis yra ši kolekcija.numatytasis srautas ()
: Grąžinti nuoseklųSrautas
objektas, kurio šaltinis yra ši kolekcija.
Tarkime, kad deklaravote šiuos dalykus java.util.Sąrašas
kintamasis ir priskyrimo išraiška:
Išvardykite internalPlanets = Arrays.asList („Merkurijus“, „Venera“, „Žemė“, „Marsas“);
Tradiciškai kartotumėte šią kolekciją taip:
už (String internalPlanet: internalPlanets) System.out.println (internalPlanet);
Šią išorinę iteraciją, kurioje daugiausia dėmesio skiriama skaičiavimui, galite pakeisti srautais pagrįsta vidine iteracija, kurioje daugiausia dėmesio skiriama skaičiavimui atlikti:
internalPlanets.stream (). forEach (System.out :: println); internalPlanets.parallelStream (). forEach (System.out :: println);
Čia internalPlanets.stream ()
ir internalPlanets.parallelStream ()
grąžinti nuoseklius ir lygiagrečius srautus į anksčiau sukurtą Sąrašas
šaltinis. Prirakintas prie grąžinto Srautas
nuorodos yra forEach (System.out :: println)
, kuri kartoja srauto objektus ir kviečia System.out.println ()
(identifikuota pagal System.out :: println
metodo nuoroda) kiekvienam objektui, kad jis išvestų eilutės vaizdą į standartinį išvesties srautą.
Numatytieji metodai gali padaryti kodą lengviau įskaitomą. Pavyzdžiui, java.util.Rinkiniai
klasė deklaruoja a negaliojantis rūšiavimas (sąrašų sąrašas, palyginamasis c)
statinis sąrašo turinio rūšiavimo metodas, atsižvelgiant į nurodytą palyginimo priemonę. „Java 8“ pridėjo a numatytasis negaliojantis rūšiavimas (palyginamasis c)
metodas Sąrašas
sąsają, kad galėtumėte parašyti labiau skaitomą myList.sort (palyginamasis);
vietoj Rinkiniai.rūšiuoti („myList“, lyginamasis);
.
Numatytasis sąsajų siūlomas metodo vaidmuo suteikė naują gyvybę „Java Collections Framework“. Galite apsvarstyti šį vaidmenį savo pačių sąsaja pagrįstose bibliotekose.