Programmēšana

Saskarnes sešas lomas

Java valodas jaunpienācēji bieži piedzīvo neskaidrības. Viņu neskaidrības lielā mērā ir saistītas ar Java eksotisko valodas iezīmju, piemēram, vispārīgo un lambdas, paleti. Tomēr pat vienkāršākas funkcijas, piemēram, saskarnes, var būt mulsinošas.

Nesen es saskāros ar jautājumu, kāpēc Java atbalsta saskarnes (izmantojot interfeiss un īsteno atslēgvārdi). Kad es sāku mācīties Java 1990. gados, uz šo jautājumu bieži atbildēja, norādot, ka saskarnes apiet Java atbalsta trūkumu vairāku ieviešanas mantojums (bērnu klases, kas tiek mantotas no vairākām vecāku klasēm). Tomēr saskarnes kalpo daudz vairāk nekā kludge. Šajā amatā es iepazīstinu ar sešām lomām, kuras saskarnes spēlē Java valodā.

Par vairākkārtēju mantošanu

Termiņš vairākkārtēja mantošana parasti lieto, lai atsauktos uz bērnu klasi, kas tiek mantota no vairākām vecāku klasēm. Java valodā šis termins vairāku ieviešanas mantojums nozīmē to pašu. Java atbalsta arī vairāku interfeisu mantojums kurā bērna saskarne var mantot no vairākām vecāku saskarnēm. Lai uzzinātu vairāk par vairākkārtēju mantojumu (ieskaitot slaveno dimanta problēmu), skatiet Wikipedia ierakstu Vairāku mantojumu.

1. loma: anotāciju veidu deklarēšana

The interfeiss atslēgvārds ir pārslogots lietošanai anotāciju veidu deklarēšanā. Piemēram, 1. saraksts parāda vienkāršu Stub anotācijas veids.

Saraksts 1. Stub.java

importēt java.lang.annotation.Retention; importēt java.lang.annotation.RetentionPolicy; @Retention (RetentionPolicy.RUNTIME) public @interface Stub {int id (); // Ar semikolu tiek pārtraukta elementa deklarācija. String dueDate (); Virknes izstrādātājs () noklusējums "nepiešķirts"; }

Stub apraksta kategoriju anotācijas (anotācijas tipa gadījumi), kas apzīmē nepabeigtus veidus un metodes. Tās deklarācija sākas ar galveni, kas sastāv no @ seko interfeiss atslēgvārds, kam seko tā nosaukums.

Šis anotācijas veids deklarē trīs elementi, kuru jūs varat iedomāties kā metožu galvenes:

  • id () atgriež uz veselu skaitli balstītu identifikatora identifikāciju
  • gala termiņš() identificē datumu, līdz kuram štats jāaizpilda ar kodu
  • izstrādātājs () identificē izstrādātāju, kurš ir atbildīgs par stumbra aizpildīšanu

Elements atgriež jebkuru vērtību, kas tam piešķirta ar anotāciju. Ja elements nav norādīts, tā noklusējuma vērtība (ievērojot noklusējums atslēgvārds deklarācijā) tiek atgriezta.

2. saraksts parāda Stub nepabeigtā kontekstā ContactMgr klase; klase un tās vientuļā metode ir anotēta ar @Stub anotācijas.

2. saraksts. ContactMgr.java

@Stub (id = 1, dueDate = "31.12.2016.") Publiskā klase ContactMgr {@Stub (id = 2, dueDate = "31.06.2016., Developer =" Marty ") public void addContact (String contactID ) {}}

Anotācijas tipa eksemplārs sākas ar @, kam seko anotācijas tipa nosaukums. Lūk, pirmais @Stub anotācija identificē sevi kā 1. numuru, kura izpildes termiņš ir 2016. gada 31. decembris. Izstrādātājs, kurš ir atbildīgs par aizpildīšanu, vēl nav piešķirts. Turpretī otrais @Stub anotācija identificē sevi kā 2. numuru, kura izpildes termiņš ir 2016. gada 31. jūnijs. Izstrādātājs, kurš ir atbildīgs par stumbra aizpildīšanu, tiek identificēts kā Marty.

Anotācijas ir jāapstrādā, lai tās varētu jebkādi izmantot. (Stub ir anotēta @Retention (RetentionPolicy.RUNTIME) lai to varētu apstrādāt.) 3. uzskaitījums parāda a StubFinder lietojumprogramma, kas ziņo par klases mācību priekšmetu @Stub anotācijas.

3. saraksts. StubFinder.java

importēt java.lang.reflect.Method; public class StubFinder {public static void main (String [] args) izmet izņēmumu {if (args.length! = 1) {System.err.println ("use: java StubFinder classfile"); atgriešanās; } Class clazz = Class.forName (argumenti [0]); if (clazz.isAnnotationPresent (Stub.class)) {Stub stub = clazz.getAnnotation (Stub.class); System.out.println ("Stub ID =" + stub.id ()); System.out.println ("Stub Date =" + stub.dueDate ()); System.out.println ("Stub Developer =" + stub.developer ()); System.out.println (); } Metode [] metodes = clazz.getMethods (); for (int i = 0; i <metodes.length; i ++) if (metodes [i] .isAnnotationPresent (Stub.class)) {Stub stub = metodes [i] .getAnnotation (Stub.class); System.out.println ("Stub ID =" + stub.id ()); System.out.println ("Stub Date =" + stub.dueDate ()); System.out.println ("Stub Developer =" + stub.developer ()); System.out.println (); }}}

Saraksts 3 galvenais () metode izmanto Java Reflection API, lai izgūtu visus @Stub anotācijas, kas prefiksē klases deklarāciju, kā arī tās metožu deklarācijas.

Apkopojiet sarakstus no 1. līdz 3. šādi:

javac * .java

Palaidiet iegūto lietojumprogrammu šādi:

java StubFinder ContactMgr

Jums jāievēro šāda izeja:

Stub ID = 1 Stub Date = 31.12.2016 Stub Developer = nepiešķirts Stub ID = 2 Stub Date = 31.06.2016 Stub Developer = Marty

Jūs varētu apgalvot, ka anotāciju veidiem un to anotācijām nav nekāda sakara ar saskarnēm. Galu galā klases deklarācijas un īsteno atslēgvārda nav. Es tomēr nepiekristu šim secinājumam.

@interface ir līdzīgs klasē ar to ievieš tipu. Tās elementi ir metodes, kas tiek ieviestas (aizkulisēs), lai atgrieztu vērtības. Elementi ar noklusējums vērtības atgriež vērtības, pat ja tās nav anotācijās, kas ir līdzīgas objektiem. Noklusējuma elementiem vienmēr jābūt anotācijā, un tie ir jādeklarē, lai atgrieztu vērtību. Tāpēc ir tā, it kā klase būtu deklarēta un ka klase īsteno saskarnes metodes.

2. loma: aprakstīt no ieviešanas neatkarīgas iespējas

Dažādas klases var piedāvāt kopēju iespēju. Piemēram, java.nio.CharBuffer, javax.swing.text.Segment, java.lang.Strings, java.lang.StringBuffer, un java.lang.StringBuilder klases nodrošina piekļuvi lasāmām sekvencēm char vērtības.

Kad klases piedāvā kopēju iespēju, šīs spējas saskarni var iegūt atkārtotai izmantošanai. Piemēram, saskarne "lasāmajai secībai char vērtības "spēja ir izvilkta java.lang.CharSequence interfeiss. CharSequence nodrošina vienotu, tikai lasāmu piekļuvi daudziem dažādiem veidiem char secības.

Pieņemsim, ka jums tika lūgts uzrakstīt nelielu lietojumprogrammu, kurā tiek uzskaitīti katra veida mazie burti CharBuffer, Stīga, un StringBuffer objektiem. Pēc dažām pārdomām, jūs varētu nākt klajā ar 4. sarakstu (es parasti izvairītos no kultūras ziņā neobjektīviem izteicieniem, piemēram, ch - "a", bet es vēlos saglabāt piemēru vienkāršu.)

4. saraksts. Freq.java (1. versija)

importēt java.nio.CharBuffer; public class Freq {public static void main (String [] args) {if (args.length! = 1) {System.err.println ("lietojums: java Freq teksts"); atgriešanās; } analizētS (args [0]); analySB (jauns StringBuffer (args [0])); analizētCB (CharBuffer.wrap (args [0])); } static void analizētCB (CharBuffer cb) {int skaits [] = jauns int [26]; while (cb.hasRemaining ()) {char ch = cb.get (); ja (ch> = 'a' && ch <= 'z') skaita [ch - 'a'] ++; } for (int i = 0; i <count.length; i ++) System.out.printf ("% c skaits ir% d% n", (i + 'a'), skaita [i]); System.out.println (); } static void analizētS (virkne s) {int skaits [] = jauns int [26]; jo (int i = 0; i = 'a' && ch <= 'z') skaita [ch - 'a'] ++; } for (int i = 0; i <count.length; i ++) System.out.printf ("% c skaits ir% d% n", (i + 'a'), skaita [i]); System.out.println (); } static void analizētSB (StringBuffer sb) {int skaits [] = jauns int [26]; jo (int i = 0; i = 'a' && ch <= 'z') skaita [ch - 'a'] ++; } for (int i = 0; i <count.length; i ++) System.out.printf ("% c skaits ir% d% n", (i + 'a'), skaita [i]); System.out.println (); }}

4. sarakstā ir trīs dažādi analizēt metodes, kā reģistrēt mazo burtu sastopamību skaitu un uzrādīt šo statistiku. Lai gan Stīga un StringBuffer varianti ir praktiski identiski (un jums varētu rasties kārdinājums izveidot vienu metodi abiem) CharBuffer variants ievērojami atšķiras.

4. saraksts atklāj daudz koda dublikātu, kas noved pie lielāka klases faila, nekā nepieciešams. Jūs varētu sasniegt to pašu statistikas mērķi, strādājot ar CharSequence interfeiss. 5. saraksts parāda alternatīvās frekvences lietojumprogrammas versiju, kuras pamatā ir CharSequence.

5. saraksts. Freq.java (2. versija)

importēt java.nio.CharBuffer; public class Freq {public static void main (String [] args) {if (args.length! = 1) {System.err.println ("lietojums: java Freq teksts"); atgriešanās; } analizēt (argumenti [0]); analizēt (jauns StringBuffer (args [0])); analizēt (CharBuffer.wrap (args [0])); } static void analizēt (CharSequence cs) {int skaits [] = jauns int [26]; jo (int i = 0; i = 'a' && ch <= 'z') skaita [ch - 'a'] ++; } for (int i = 0; i <count.length; i ++) System.out.printf ("% c skaits ir% d% n", (i + 'a'), skaita [i]); System.out.println (); }}

5. saraksts atklāj daudz vienkāršāku lietojumu, kas ir saistīts ar kodēšanu analizēt () saņemt a CharSequence arguments. Jo katrs no Stīga, StringBuffer, un CharBuffer īsteno CharSequence, ir likumīgi nodot šāda veida gadījumus analizēt ().

Vēl viens piemērs

Izteiksme CharBuffer.wrap (argumenti [0]) ir vēl viens piemērs, kā nokārtot a Stīga iebilst pret tipa parametru CharSequence.

Rezumējot, interfeisa otrā loma ir aprakstīt no ieviešanas neatkarīgu spēju. Kodējot interfeisu (piemēram, CharSequence), nevis klasē (piemēram, Stīga, StringBuffervai CharBuffer), jūs izvairīsities no koda dublikāta un ģenerēsit mazākus klases failus. Šajā gadījumā es panācu samazinājumu par vairāk nekā 50%.

3. loma: bibliotēkas evolūcijas veicināšana

Java 8 iepazīstināja mūs ar ārkārtīgi noderīgo lambda valodas funkciju un Streams API (koncentrējoties uz to, kāds skaitļojums jāveic, nevis uz to, kā tas būtu jāveic). Lambdas un straumes ļauj izstrādātājiem daudz vienkāršāk ieviest paralēlismu savās lietojumprogrammās. Diemžēl Java kolekciju ietvars nevarēja izmantot šīs iespējas bez plaša pārrakstīšanas.

Lai ātri uzlabotu kolekcijas lietošanai kā straumes avotus un galamērķus, atbalstiet vietni noklusējuma metodes (zināms arī kā pagarināšanas metodes), kas nav statiskas metodes un kuru galvenes tiek pievienotas ar noklusējums atslēgvārds un piegādes koda pamatteksti tika pievienoti Java saskarnes funkcijai. Noklusējuma metodes pieder saskarnēm; tos neievieš (bet tos var ignorēt) klases, kas ievieš saskarnes. Arī tos var izsaukt, izmantojot objektu atsauces.

Kad noklusējuma metodes ir kļuvušas par valodas daļu, programmai tika pievienotas šādas metodes java.util.Kolekcija interfeiss, lai nodrošinātu tiltu starp kolekcijām un straumēm:

  • noklusējuma straume parallelStream (): Atgrieziet (iespējams) paralēli java.util.stream.Stream objekts, kura avots ir šī kolekcija.
  • noklusējuma straumes straume (): Atgrieziet secību Straumēt objekts, kura avots ir šī kolekcija.

Pieņemsim, ka esat paziņojis sekojošo java.util.List mainīgā un piešķiršanas izteiksme:

Uzskaitiet innerPlanets = Arrays.asList ("Merkurs", "Venēra", "Zeme", "Marss");

Jūs tradicionāli atkārtosiet šo kolekciju šādi:

par (String internalPlanet: internalPlanets) System.out.println (iekŠējaisPlanet);

Šo ārējo atkārtojumu, kas koncentrējas uz aprēķina veikšanu, varat aizstāt ar iekšēju straumēm balstītu iterāciju, kas koncentrējas uz to, kāda skaitļošana jāveic, šādi:

internalPlanets.stream (). forEach (System.out :: println); internalPlanets.parallelStream (). forEach (System.out :: println);

Šeit, internalPlanets.stream () un innerPlanets.parallelStream () atgriezt secīgās un paralēlās straumes iepriekš izveidotajā Saraksts avots. Pie atgriezuma pieķēdēts Straumēt atsauces ir forEach (System.out :: println), kas atkārtojas straumes objektos un izsauc System.out.println () (identificēts ar System.out :: println Metodes atsauce) katram objektam, lai tā virknes attēlojumu izvadītu standarta izvades straumē.

Noklusējuma metodes var padarīt kodu vieglāk lasāmu. Piemēram, java.util.Kolekcijas klase deklarē a void sort (Sarakstu saraksts, C salīdzinātājs) statiskā metode saraksta satura šķirošanai, ievērojot norādīto salīdzinātāju. Java 8 pievienoja a noklusējuma noklusējuma šķirošana (c) salīdzinātājs metodi Saraksts interfeisu, lai jūs varētu rakstīt lasāmāku myList.sort (salīdzinātājs); tā vietā Collections.sort (myList, salīdzinātājs);.

Saskarņu piedāvātā noklusējuma metode ir piešķīrusi jaunu dzīvību Java kolekciju ietvarstruktūrai. Jūs varētu apsvērt šo lomu savām mantotajām saskarnēm balstītajām bibliotēkām.

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