Programavimas

Šeši sąsajos vaidmenys

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 kodu
  • programuotojas() 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.StringBufferir 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, Stygosir „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.

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