Programiranje

Šest vlog vmesnika

Novinci v jeziku Java so pogosto zmedeni. Njihova zmedenost je v veliki meri posledica palete eksotičnih jezikovnih lastnosti, kot so generiki in lambda. Vendar pa lahko celo preprostejše funkcije, kot so vmesniki, zmedejo.

Pred kratkim sem se soočil z vprašanjem, zakaj Java podpira vmesnike (prek vmesnik in izvaja ključne besede). Ko sem se v devetdesetih letih začel učiti Javo, so na to vprašanje pogosto odgovorili z izjavo, da vmesniki obvladujejo pomanjkanje podpore Java za dedovanje večkratne izvedbe (podrejeni razredi, ki dedujejo iz več nadrejenih razredov). Vendar vmesniki služijo veliko več kot le gonilo. V tem prispevku predstavljam šest vlog, ki jih imajo vmesniki v jeziku Java.

O večkratnem dedovanju

Izraz večkratno dedovanje se pogosto uporablja za sklicevanje na podrejeni razred, ki podeduje več roditeljskih razredov. V Javi izraz dedovanje večkratne izvedbe pomeni isto stvar. Java podpira tudi dedovanje več vmesnikov v katerem lahko podrejeni vmesnik podeduje iz več nadrejenih vmesnikov. Če želite izvedeti več o večkratnem dedovanju (vključno s slavnim problemom diamantov), ​​si oglejte vnos Wikipedijevega več dedovanja.

Vloga 1: Navajanje vrst pripisov

The vmesnik ključna beseda je preobremenjena za uporabo pri prijavljanju vrst pripisov. Na primer, seznam 1 predstavlja preprosto Stub vrsta pripisa.

Seznam 1. Stub.java

import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention (RetentionPolicy.RUNTIME) public @interface Stub {int id (); // Podpičje zaključi izjavo elementa. String dueDate (); String razvijalec () privzeto "nedodeljen"; }

Stub opisuje kategorijo opombe (primerki tipa pripisov), ki označujejo nedokončane vrste in metode. Njegova izjava se začne z glavo, sestavljeno iz @ čemur sledi vmesnik ključni besedi, ki ji sledi ime.

Ta vrsta pripisa označuje tri elementi, ki si ga lahko omislite kot glavo metode:

  • id () vrne identifikator, ki temelji na celoštevilskem številu
  • rok() določa datum, do katerega je treba škrbino izpolniti s kodo
  • razvijalec () identificira razvijalca, odgovornega za polnjenje škrbine

Element vrne kakršno koli vrednost, ki mu jo dodeli pripis. Če element ni določen, je njegova privzeta vrednost (po privzeto vrnjena ključna beseda v izjavi).

Seznam 2 prikazuje Stub v kontekstu nedokončanega Kontakt razred; razred in njegova samotna metoda so označeni z @Stub opombe.

Seznam 2. ContactMgr.java

@Stub (id = 1, dueDate = "31.12.2016") javni razred ContactMgr {@Stub (id = 2, dueDate = "31.06.2016", razvijalec = "Marty") public void addContact (String contactID ) {}}

Primerek tipa pripisa se začne z @, ki mu sledi ime vrste pripisa. Tukaj, prvi @Stub Pripis se označi kot številka 1 z datumom zapadlosti 31. decembra 2016. Razvijalec, odgovoren za polnjenje škrbine, še ni dodeljen. Nasprotno pa drugi @Stub Pripis se označi kot številka 2 z datumom zapadlosti 31. junija 2016. Razvijalec, odgovoren za polnjenje škrbine, je označen kot Marty.

Opombe je treba obdelati, da bodo koristne. (Stub je označeno @Retention (RetentionPolicy.RUNTIME) tako da ga je mogoče obdelati.) Na seznamu 3 so predstavljeni a StubFinder aplikacija, ki poroča o razredu @Stub opombe.

Seznam 3. StubFinder.java

uvoz java.lang.reflect.Method; javni razred StubFinder {public static void main (String [] args) vrže izjemo {if (args.length! = 1) {System.err.println ("uporaba: java StubFinder classfile"); vrnitev; } Class clazz = Class.forName (args [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 (); } Metoda [] metode = clazz.getMethods (); for (int i = 0; i <methods.length; i ++) if (methods [i] .isAnnotationPresent (Stub.class)) {Stub stub = methods [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 (); }}}

Seznam 3 glavni () metoda uporablja Java-ov Reflection API za pridobivanje vseh @Stub pripise, ki predpišejo deklaracijo razreda in njene deklaracije metod.

Sestavi seznam 1 do 3, kot sledi:

javac * .java

Zaženite nastalo aplikacijo, kot sledi:

java StubFinder KontaktMgr

Upoštevati morate naslednje rezultate:

Stub ID = 1 Stub Date = 31.12.2016 Razvijalec Stub = nerazporejeni ID Stub = 2 Stub Date = 31.06.2016 Razvijalec Stub = Marty

Lahko trdite, da vrste pripisov in njihovi pripisi nimajo nič skupnega z vmesniki. Konec koncev, izjave razredov in izvaja ključna beseda ni prisotna. Vendar se s tem sklepom ne bi strinjal.

@interface je podoben razred v tem, da uvaja tip. Njeni elementi so metode, ki se izvajajo (v ozadju) za vrnitev vrednosti. Elementi z privzeto vrednosti vrnejo vrednosti, tudi če niso v pripisih, ki so podobni predmetom. V pripisu morajo biti vedno prisotni elementi, ki niso privzeti in jih je treba prijaviti, da vrnejo vrednost. Zato je kot da je bil razred razglašen in da razred izvaja metode vmesnika.

Vloga 2: Opis zmogljivosti, neodvisnih od izvedbe

Različni razredi lahko nudijo skupno sposobnost. Na primer java.nio.CharBuffer, javax.swing.text.Segment, java.lang.String, java.lang.StringBuffer, in java.lang.StringBuilder razredi omogočajo dostop do berljivih zaporedij char vrednote.

Kadar razredi ponujajo skupno sposobnost, lahko vmesnik te sposobnosti izvlečemo za ponovno uporabo. Na primer vmesnik do "berljivega zaporedja char vrednosti "je bila izvlečena v java.lang.CharSequence vmesnik. CharSequence omogoča enoten, samo za branje dostop do številnih vrst char zaporedja.

Recimo, da ste bili pozvani, da napišete majhno aplikacijo, ki šteje število pojavitev posamezne male črke v CharBuffer, Vrvica, in StringBuffer predmetov. Po premisleku boste morda prišli do seznama 4. (Običajno bi se izogibal kulturno pristranskim izrazom, kot je ch - "a", vendar želim, da je primer preprost.)

Seznam 4. Freq.java (različica 1)

uvoz java.nio.CharBuffer; javni razred Freq {javna statična void main (String [] args) {if (args.length! = 1) {System.err.println ("uporaba: besedilo java Freq"); vrnitev; } analyS (argumenti [0]); analySB (nov StringBuffer (args [0])); analizaCB (CharBuffer.wrap (args [0])); } statična analiza prazninCB (CharBuffer cb) {štetje int [] = novo int [26]; while (cb.hasRemaining ()) {char ch = cb.get (); če (ch> = 'a' && ch <= 'z') šteje [ch - 'a'] ++; } for (int i = 0; i <counts.length; i ++) System.out.printf ("Število% c je% d% n", (i + 'a'), šteje [i]); System.out.println (); } static void analyS (String s) {int counts [] = new int [26]; za (int i = 0; i = 'a' && ch <= 'z') šteje [ch - 'a'] ++; } for (int i = 0; i <counts.length; i ++) System.out.printf ("Število% c je% d% n", (i + 'a'), šteje [i]); System.out.println (); } statična praznina analySB (StringBuffer sb) {int counts [] = new int [26]; za (int i = 0; i = 'a' && ch <= 'z') šteje [ch - 'a'] ++; } for (int i = 0; i <counts.length; i ++) System.out.printf ("Število% c je% d% n", (i + 'a'), šteje [i]); System.out.println (); }}

Seznam 4 predstavlja tri različne analizirati metode za beleženje števila pojavitev malih črk in izpis te statistike. Čeprav je Vrvica in StringBuffer različice so praktično enake (in morda vas bo zamikalo ustvariti eno samo metodo za obe), CharBuffer varianta se bistveno razlikuje.

Seznam 4 razkriva veliko podvojenih kod, kar vodi do večje datoteke predavanj, kot je potrebno. Isti statistični cilj bi lahko dosegli z delom z CharSequence vmesnik. Seznam 5 predstavlja nadomestno različico frekvenčne aplikacije, na kateri temelji CharSequence.

Seznam 5. Freq.java (različica 2)

uvoz java.nio.CharBuffer; javni razred Freq {javna statična void main (String [] args) {if (args.length! = 1) {System.err.println ("uporaba: besedilo java Freq"); vrnitev; } analizirati (argumenti [0]); analizirati (nov StringBuffer (args [0])); analizirajte (CharBuffer.wrap (args [0])); } statična analiza praznin (CharSequence cs) {int counts [] = new int [26]; za (int i = 0; i = 'a' && ch <= 'z') šteje [ch - 'a'] ++; } for (int i = 0; i <counts.length; i ++) System.out.printf ("Število% c je% d% n", (i + 'a'), šteje [i]); System.out.println (); }}

Seznam 5 razkriva veliko preprostejšo aplikacijo, ki je posledica kodifikacije analizirati () prejeti a CharSequence prepir. Ker vsak od Vrvica, StringBuffer, in CharBuffer izvaja CharSequence, je zakonito prenašati primere teh vrst analizirati ().

Še en primer

Izraz CharBuffer.wrap (argumenti [0]) je še en primer podajanja Vrvica objekt parametra tipa CharSequence.

Če povzamemo, druga vloga vmesnika je opisati zmogljivost, neodvisno od izvedbe. S kodiranjem vmesnika (kot je CharSequence) namesto v razred (na primer Vrvica, StringBuffer, ali CharBuffer), se izognete podvojenim kodam in ustvarite manjše datoteke datotek. V tem primeru sem dosegel zmanjšanje za več kot 50%.

Vloga 3: Olajšanje razvoja knjižnic

Java 8 nas je seznanil z izjemno uporabno funkcijo lambda jezika in API-jem Streams (s poudarkom na tem, kakšno računanje je treba izvesti, ne pa na to, kako naj bo izvedeno). Lambde in potoki razvijalcem veliko olajšajo uvajanje vzporednosti v svoje aplikacije. Na žalost ogrodje zbirk Java ni mogel izkoristiti teh zmožnosti, ne da bi potreboval obsežno prepisovanje.

Če želite hitro izboljšati zbirke za uporabo kot viri toka in cilji, podpora za privzete metode (poznan tudi kot metode podaljšanja), ki so nestatične metode, katerih glave imajo predpono privzeto ključna beseda in ki oskrbujejo kode telesa, je bila dodana vmesniku Java. Privzete metode pripadajo vmesnikom; jih ne izvajajo (lahko pa jih preglasijo) razredi, ki izvajajo vmesnike. Prav tako jih je mogoče priklicati prek referenc objekta.

Ko so privzete metode postale del jezika, so bile naslednje metode dodane v java.util.Collection vmesnik, ki zagotavlja most med zbirkami in tokovi:

  • privzet tok Stream parallelStream (): Vrni (morda) vzporednik java.util.stream.Stream predmet s to zbirko kot izvorom.
  • privzeti tok pretoka (): Vrni zaporedje Tok predmet s to zbirko kot izvorom.

Recimo, da ste izjavili naslednje java.util.List izraz spremenljivke in dodelitve:

Seznam innerPlanets = Arrays.asList ("Merkur", "Venera", "Zemlja", "Mars");

Tradicionalno bi ponavljali to zbirko, kot sledi:

za (String innerPlanet: innerPlanets) System.out.println (innerPlanet);

To zunanjo ponovitev, ki se osredotoča na to, kako izvesti izračun, lahko nadomestite z notranjo ponovitvijo, ki temelji na toku, ki se osredotoča na to, kateri izračun naj izvede, kot sledi:

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

Tukaj, innerPlanets.stream () in innerPlanets.parallelStream () vrni zaporedni in vzporedni tok predhodno ustvarjenemu Seznam vir. Priklenjen na vrnjene Tok reference je forEach (System.out :: println), ki se ponovi nad predmeti toka in prikliče System.out.println () (opredeljeno s strani System.out :: println sklic na metodo) za vsak objekt, da prikaže svojo nizno predstavitev v standardni izhodni tok.

Privzete metode lahko naredijo kodo bolj berljivo. Na primer java.util.Collections razred razglasi a void sort (seznam seznamov, primerjalnik c) statična metoda za razvrščanje vsebine seznama, ki je predmet določene primerjalne enote. Java 8 je dodal a privzeta void sort (Primerjalnik c) metoda do Seznam vmesnik, tako da lahko pišete bolj berljivo myList.sort (primerjalnik); namesto Collections.sort (myList, primerjalnik);.

Privzeta vloga metode, ki jo ponujajo vmesniki, je dala novo življenje okolju Java Collections Framework. To vlogo lahko razmislite za lastne knjižnice, ki temeljijo na starejših vmesnikih.

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