Programmēšana

Atkarība no tipa Java, 1. daļa

Izpratne par tipu savietojamību ir būtiska, lai rakstītu labas Java programmas, taču nezinātājiem var šķist ļoti akadēmiska Java valodu elementu dispersiju mijiedarbība. Šis raksts ir paredzēts programmatūras izstrādātājiem, kas gatavi risināt šo problēmu! 1. daļa atklāj kovariētās un pretrunīgās attiecības starp vienkāršākiem elementiem, piemēram, masīvu tipiem un vispārīgiem tipiem, kā arī īpašo Java valodas elementu, aizstājējzīmi. 2. daļā tiek pētīta tipu atkarība un dispersija kopējos API piemēros un lambda izteiksmēs.

lejupielādēt Lejupielādēt avotu Iegūstiet šī raksta "Tipa atkarība Java 1. daļā" avota kodu. JavaWorld izveidoja Dr Andreas Solymosi.

Jēdzieni un terminoloģija

Pirms nonākam kovariācijas un pretrunīguma attiecībās starp dažādiem Java valodas elementiem, būsim pārliecināti, ka mums ir kopīgs konceptuāls ietvars.

Saderība

Objektorientētā programmēšanā saderība attiecas uz virzītu saistību starp tipiem, kā parādīts 1. attēlā.

Andreas Solymosi

Mēs sakām, ka divi veidi ir savietojams Java, ja ir iespējams pārsūtīt datus starp tipu mainīgajiem. Datu pārsūtīšana ir iespējama, ja kompilators to akceptē un to veic, izmantojot piešķiršanu vai parametru nodošanu. Kā piemērs, īss ir savietojams ar int jo norīkojums intVariaable = īss Mainīgais; ir iespējams. Bet būla nav saderīgs ar int jo norīkojums intVariable = būla mainīgais; nav iespējams; sastādītājs to nepieņems.

Tā kā saderība dažkārt ir vērsta saistība T1 ir savietojams ar T2 bet T2 nav saderīgs ar T1, vai ne tādā pašā veidā. Mēs to redzēsim tālāk, kad apspriedīsim tiešu vai netiešu saderību.

Svarīgi ir tas, ka ir iespējama savietojamība starp atsauces tipiem tikai tipa hierarhijas ietvaros. Visi klases veidi ir saderīgi ar Objekts, piemēram, tāpēc, ka visas klases netieši manto no Objekts. Vesels skaitlis nav saderīgs ar Peldēttomēr tāpēc Peldēt nav grupas superklase Vesels skaitlis. Vesels skaitlisir savietojams ar Skaits, jo Skaits ir (abstrakta) Vesels skaitlis. Tā kā tie atrodas viena tipa hierarhijā, kompilators pieņem uzdevumu numberReference = integerReference;.

Mēs runājam par netieši vai nepārprotams saderība atkarībā no tā, vai savietojamība ir skaidri jāmarķē vai nē. Piemēram, īss ir netieši savietojams ar int (kā parādīts iepriekš), bet ne otrādi: uzdevums shortVariable = mainīgs; nav iespējams. Tomēr īss ir nepārprotami savietojams ar int, jo uzdevums shortVariaable = (īss) mainīgs; ir iespējams. Šeit mums jāatzīmē saderība ar liešana, kas pazīstams arī kā tipa pārveidošana.

Līdzīgi starp atsauces veidiem: integerReference = numursReference; nav pieņemams, tikai integerReference = (Integer) skaitlisReference; tiktu pieņemts. Tāpēc Vesels skaitlis ir netieši savietojams ar Skaits bet Skaits ir tikai nepārprotami savietojams ar Vesels skaitlis.

Atkarība

Veids var būt atkarīgs no citiem veidiem. Piemēram, masīva tips int [] atkarīgs no primitīvā tipa int. Līdzīgi arī vispārīgais tips ArrayList ir atkarīgs no veida Klients. Metodes var būt atkarīgas arī no veida, atkarībā no to parametru veidiem. Piemēram, metode tukšs pieaugums (vesels skaitlis i); atkarīgs no veida Vesels skaitlis. Dažas metodes (piemēram, daži vispārīgi veidi) ir atkarīgas no vairāk nekā viena veida, piemēram, metodes, kurām ir vairāki parametri.

Kovārija un pretrunīgums

Kovariancija un pretrunīgums nosaka saderību, pamatojoties uz tipiem. Jebkurā gadījumā dispersija ir virzīta attiecība. Kovariance var tulkot kā "atšķirīgi tajā pašā virzienā" vai ar-atšķirīgs, tā kā pretrunīgums nozīmē "atšķirīgs pretējā virzienā" vai pret-atšķirīgs. Kovariāna un kontravarianta veidi nav vienādi, taču starp tiem pastāv korelācija. Nosaukumi nozīmē korelācijas virzienu.

Tātad, kovariācija nozīmē, ka divu veidu savietojamība nozīmē no tiem atkarīgo tipu savietojamību. Ņemot vērā tipu savietojamību, var pieņemt, ka atkarīgie tipi ir atšķirīgi, kā parādīts 2. attēlā.

Andreas Solymosi

Programmas saderība T1 uz T2 nozīmē saderību ar A (T.1) līdz A (T.2). Atkarīgais tips A (T) tiek saukts kovariāns; vai precīzāk, A (T.1) ir līdzīgs A (T.2).

Vēl viens piemērs: tāpēc, ka uzdevums numberArray = integerArray; ir iespējams (vismaz Java valodā), masīvu veidi Vesels skaitlis[] un Skaits [] ir mainīgi. Tātad, mēs to varam teikt Vesels skaitlis[] ir netieši kovārijs uz Skaits []. Un, lai gan nav otrādi - uzdevums integerArray = skaitlisArray; nav iespējams - norīkojums ar tipa liešanu (integerArray = (Integer []) skaitlis Array;) ir iespējams; tāpēc mēs sakām: Skaits [] ir nepārprotami kovārijs uz Vesels skaitlis[] .

Apkopot: Vesels skaitlis ir netieši savietojams ar Skaitstāpēc Vesels skaitlis[] ir netieši kopīgs ar Skaits [], un Skaits [] ir nepārprotami kopīgs ar Vesels skaitlis[] . 3. attēls ilustrē.

Andreas Solymosi

Vispārīgi runājot, mēs varam teikt, ka masīvu veidi Java ir atšķirīgi. Kovariācijas piemēri starp vispārīgiem tipiem tiks aplūkoti vēlāk rakstā.

Pretrunīgums

Tāpat kā kovariācija, arī pretrunīgums ir a vadīts attiecības. Kaut arī kovariācija nozīmē ar-atšķirīgs, pretrunīgums nozīmē pret-atšķirīgs. Kā jau iepriekš minēju, nosaukumi izsaka korelācijas virzienu. Ir arī svarīgi atzīmēt, ka dispersija nav tipu atribūts, bet gan tikai atkarīgs veidi (piemēram, masīvi un vispārīgi veidi, kā arī metodes, kuras es aplūkošu 2. daļā).

Atkarīgs tips, piemēram, A (T) tiek saukts pretrunīgs ja saderība ar T1 uz T2 nozīmē saderību ar A (T.2) līdz A (T.1). 4. attēls ilustrē.

Andreas Solymosi

Valodas elements (tips vai metode) A (T) atkarībā no T ir kovariāns ja saderība ar T1 uz T2 nozīmē saderību ar A (T.1) līdz A (T.2). Ja saderība T1 uz T2 nozīmē saderību ar A (T.2) līdz A (T.1), tad tips A (T) ir pretrunīgs. Ja saderība T1 starp T2 nenozīmē nekādu savietojamību starp A (T.1) un A (T.2), tad A (T) ir nemainīgs.

Masīvu veidi Java nav netieši pretrunīgi, bet tie var būt skaidri pretrunīgi , tāpat kā vispārīgie veidi. Piedāvāšu dažus piemērus vēlāk rakstā.

No tipa atkarīgi elementi: metodes un veidi

Java valodā no tipa atkarīgie elementi ir metodes, masīvu veidi un vispārīgi (parametrizēti) tipi. Metodes ir atkarīgas no to parametru veidiem. Masīva tips, T [], ir atkarīgs no tā elementu veidiem, T. Vispārējs veids G ir atkarīgs no tā tipa parametra, T. 5. attēls ilustrē.

Andreas Solymosi

Pārsvarā šajā rakstā galvenā uzmanība tiek pievērsta tipu savietojamībai, lai gan 2. daļas beigās es pieskaršos metožu saderībai.

Netieša un skaidra tipa savietojamība

Agrāk jūs redzējāt tipu T1 būtne netieši (vai nepārprotami) savietojams ar T2. Tas ir taisnība tikai tad, ja tiek piešķirts tipa mainīgais T1 uz tipa mainīgo T2 ir atļauts bez (vai ar) marķēšanas. Tipa apraide ir visizplatītākais veids, kā atzīmēt skaidru saderību:

 variableOfTypeT2 = variableOfTypeT1; // netiešais saderīgais mainīgaisOfTypeT2 = (T2) variableOfTypeT1; // nepārprotami savietojams 

Piemēram, int ir netieši savietojams ar ilgi un skaidri saderīgs ar īss:

 int mainīgais = 5; long longVariaable = intVariable; // netieši saderīgs īss īss mainīgais = (īss) mainīgs; // nepārprotami savietojams 

Netieša un skaidra saderība pastāv ne tikai uzdevumos, bet arī parametru pārsūtīšanā no metodes izsaukuma uz metodes definīciju un atpakaļ. Kopā ar ievades parametriem tas nozīmē arī funkcijas rezultāta nodošanu, ko jūs darītu kā izvades parametru.

Pieraksti to būla nav saderīgs ar jebkuru citu tipu, kā arī primitīvs un atsauces tips nekad nevar būt saderīgi.

Metodes parametri

Mēs sakām, metode nolasa ievades parametrus un raksta izvades parametrus. Primitīvu tipu parametri vienmēr ir ievades parametri. Funkcijas atgriešanās vērtība vienmēr ir izejas parametrs. Atsauces tipu parametri var būt abi: ja metode maina atsauci (vai primitīvu parametru), izmaiņas paliek metodē (tas nozīmē, ka pēc zvana tās nav redzamas ārpus metodes - tas ir pazīstams kā zvans pēc vērtības). Ja metode maina minēto objektu, tomēr izmaiņas paliek pēc atgriešanās no metodes - tas ir pazīstams kā zvans pēc atsauces.

(Atsauces) apakštips ir netieši savietojams ar tā supertipu, un supertips ir tieši saderīgs ar tā apakštipu. Tas nozīmē, ka atsauces tipi ir saderīgi tikai to hierarhijas nozarē - netieši uz augšu un tieši uz leju:

 referenceOfSuperType = referenceOfSubType; // netiešā saderīgā atsauceOfSubType = (SubType) atsauceOfSuperType; // nepārprotami savietojams 

Java kompilators parasti pieļauj netiešu saderību ar uzdevumu tikai ja pastāv risks zaudēt informāciju izpildlaika laikā starp dažādiem tipiem. (Tomēr ņemiet vērā, ka šī kārtula nav derīga, lai zaudētu precizitāti, piemēram, uzdevumā no int peldēt.) Piemēram, int ir netieši savietojams ar ilgi jo a ilgi mainīgais tur katru int vērtība. Turpretī a īss mainīgajam nav neviena int vērtības; tādējādi starp šiem elementiem ir atļauta tikai skaidra savietojamība.

Andreas Solymosi

Ņemiet vērā, ka netiešā saderība 6. attēlā pieņem, ka saistība ir pārejošs: īss ir savietojams ar ilgi.

Līdzīgi tam, kā redzat 6. attēlā, vienmēr ir iespējams piešķirt apakštipa atsauci int supertipa atsauce. Paturiet prātā, ka tas pats uzdevums otrā virzienā varētu iemest a ClassCastException, tāpēc Java kompilators to pieļauj tikai ar tipu liešanu.

Kovariāts un pretrunas masīvu tipiem

Java daži masīvu veidi ir kovarianti un / vai pretrunīgi. Kovariācijas gadījumā tas nozīmē, ka, ja T ir savietojams ar U, pēc tam T [] ir saderīgs arī ar U []. Pretrunu gadījumā tas nozīmē U [] ir savietojams ar T []. Primitīvu veidu masīvi Java ir nemainīgi:

 longArray = intArray; // tipa kļūda shortArray = (īss []) intArray; // tipa kļūda 

Atsauces tipu masīvi ir netieši kovārijs un skaidri pretrunīgitomēr:

 SuperType [] superArray; SubType [] subArray; ... superArray = subArray; // implicit covariant subArray = (SubType []) superArray; // nepārprotams pretrunīgs 
Andreas Solymosi

7. attēls. Netiešā kovariācija masīviem

Tas praktiski nozīmē to, ka masīva komponentu piešķiršana varētu mest ArrayStoreException izpildlaika laikā. Ja masīva atsauce uz SuperType atsauces uz masīva objektu Apakštips, un pēc tam vienu no tā komponentiem piešķir a SuperType objektu, tad:

 superArray [1] = jauns SuperType (); // iemet ArrayStoreException 

To dažreiz sauc par kovariācijas problēma. Patiesā problēma ir ne tik daudz izņēmums (no kura varētu izvairīties, programmējot disciplīnu), bet gan tas, ka virtuālajai mašīnai izpildlaikā jāpārbauda katrs masīva elementa uzdevums. Tas padara Java efektivitāti neizdevīgāku salīdzinājumā ar valodām bez kovariances (kur ir aizliegts saderīgs masīva atsauču piešķiršana) vai tādām valodām kā Scala, kur kovarianciju var izslēgt.

Kovariances piemērs

Vienkāršā piemērā masīva atsauce ir veida Objekts [] bet masīva objekts un elementi ir dažādās klasēs:

 Object [] objectArray; // masīva atsauces objektsArray = jauna virkne [3]; // masīva objekts; saderīgs piešķiršanas objekts Array [0] = jauns vesels skaitlis (5); // iemet ArrayStoreException 

Kovariācijas dēļ sastādītājs nevar pārbaudīt masīva elementu pēdējā piešķīruma pareizību - JVM to dara un ar ievērojamiem izdevumiem. Tomēr kompilators var optimizēt izdevumus, ja starp masīvu tipiem netiek izmantota veidu saderība.

Andreas Solymosi

Atcerieties, ka Java valodā dažu veidu atsauces mainīgajiem ir aizliegts atsaukties uz tā supertipa objektu: 8. attēlā redzamās bultiņas nedrīkst būt vērstas uz augšu.

Varianti un aizstājējzīmes vispārīgos veidos

Vispārējie (parametrizētie) tipi ir netieši nemainīgs Java valodā, kas nozīmē, ka dažādi vispārēja veida eksemplāri nav savstarpēji savietojami. Pat veida liešana neizraisīs saderību:

 Vispārējs superGeneric; Generic subGeneric; subGeneric = (Vispārīgi) superGeneric; // tipa kļūda superGeneric = (Generic) subGeneric; // tipa kļūda 

Tipa kļūdas rodas, lai arī subGeneric.getClass () == superGeneric.getClass (). Problēma ir tā, ka metode getClass () nosaka neapstrādāto tipu - tāpēc tipa parametrs nepieder pie metodes paraksta. Tādējādi abu metožu deklarācijas

 void metode (Generic p); void metode (Generic p); 

nedrīkst rasties kopā saskarnes (vai abstraktas klases) definīcijā.

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