4. Sintaksė ir semantika
Kadangi Java remiasi daugiausia C/C++ kalbomis, tie kurie moka šias kalbas ras šiame skyriuje daug pažįstamų dalykų. Java kūrėjai turėjo paprastą tikslą: jie norėjo panaudoti gerąsias C/C++ savybes perkeliant ją į Interneto ir Intraneto panaudojimo sritis. Kartu Java turėjo išspręsti silpnąsias C/C++ savybes, t.y. saugumo, perkeliamumo ir palaikomumo problemas. Jie taip pat pridėjo daugelio gijų palaikymą ir išimčių (exception ) apdorojimą, kad būtų lengviau programuoti Internetui. Todėl, skirtumai tarp C/C++ ir Java daugiausiai atsispindi paminėtose kategorijose.
Dauguma šio skyriaus informacijos buvo aprašyta pagal Java kalbos specifikaciją 1.0. Java vis dar keičiasi, dabar vis plačiau naudojama Java 2, ateityje reikia tikėtis naujų pasikeitimų. Kalbos konstruktoriai vis dar įtraukia kai kuriuos anksčiau nenaudotus raktinius žodžius ir pasiūlo naujų.
Šitas skyrius galės tarnauti kaip nuoroda, kur jūs galėsite grįžti vėl ir vėl iškilus programavimo problemom. Todėl rekomenduoju visiems bent trumpai susipažinti su šiuo skyriumi. Ypač, net patyrusiems programuotojams, reikėtų atkreipti dėmesį į masyvai ir išimtys (exceptions ) skyrelius. Java apdoroja masyvus ir išimtis (exceptions ) skirtingai, nei jūs galite tikėtis remiantis kitų programavimo kalbų žiniomis.
Šiame skyriuje mes aptarsime tokius Java sintaksės elementus:
Vardas (identifikatorius) yra techninis terminas naudojamas pavadinti mūsų programos elementus. Viskas ką mes sukuriame mūsų Java programoje, t.y. kintamieji, metodai ir klasės, yra pavadinami vardais. Identifikatorius yra sudarytas iš unikodo simbolių sekos. "Kodėl unikodo? Niekada negirdėjau apie tokį." - galite sau pasakyti.
Java buvo padaryta kad būti lengvai perkeliama ne tik per kompiuterių platformas bet taip pat ir per nacionalinius barjerus. Daugiakalbiškumo palaikymas tapo aktuali tema kompanijoms, kurios varžėsi dėl savo produktų panaudojimas globaliose rinkose. Anksčiau dauguma kompiuterinių programų buvo rašomos anglų kalba. Ne anglakalbiai šalių programuotojai buvo priversti programuoti užsienio kalba. Kompiuteriai pritraukė aibę programuotojų su poreikiu prakalbinti programas savo šalių kalba. Čia unikodas ir ateina į pagalbą.
Unikodas buvo sukurtas unikodo konsorciumo ir buvo pirmą kartą viešai paskelbtas 1990. Jis padarytas užkoduoti daugumą modernių ir istorinių kalbų. Kiekvienam simboliui išsaugoti buvo paskirta 16 bitų. Dauguma vartotojų yra tikriausiai pažįstami su ASCII simbolių seka, kuri naudoja 7 bitus kad apibrėžti kiekvieną simbolį. Unikodas naudoja ekstra bitus, kad pridėti daugeliui kalbų būdingus simbolius ir suteikti diakritinius (atskirtinius) ženklus. Diakritiniai ženklai naudojami parodyti kaip žodis yra kirčiuotas. Daugelis ne anglų kalbų naudoja diakritinius simbolius. Lietuvių kalba turi taip pat 9 (ą,č,ę,ė,į,š,ų,ū,ž) simbolius, kurių nėra Lotynų abėcėlėje. Lietuviško teksto spausdinimo problemą mes jau gvildenome antrame skyriuje Lietuviško teksto spausdinimas skyrelyje.
Java programos yra rašomos unikodu ir visos eilutės ir simboliai yra išsaugojami kaip 16 bitų unikodo simboliai. Ar jums reikia išmokti naujas simbolių eilės reikšmes? Laimei, tai visai nebūtina. Unikodas tiesiog praplečia jūsų programavimo galimybes. Jeigu jūs anksčiau programas rašėte anglų kalba, galite tęsti tai ir toliau. Java kompiliatorius konvertuos kiekvieną ASCII failą į ekvivalentų unikodinį failą ir todėl visai nebūtina, kad Javos programos tekstas iš karto būtų rašomas naudojant unikodo simbolius.
Sun sprendimas panaudoti unikodą turi tam tikrų pasekmių. Java sukompiliuotas kodas užims maždaug dvigubai daugiau vietos. Tačiau tai nėra esminis trūkumas, nes Java nesivaržo dėl programos kompaktiškumo ir vykdymo greičio rekordų. Java pagrindinė paskirtis padaryti savo programas lengvai perkeliamas Internetu ir nepriklausomas nuo vartotojų kompiuterių platformų. Šie tikslai nesuderinami su atminties taupymu ir labai greitu skaičiavimu ir suteikiami unikodo privalumai yra neginčytini. Jei pradėsite pateikinėti savo Java programinius produktus tarptautinei rinkai, dar kartą įsitikinsite unikodo nauda.
Jeigu norite daugiau informacijos apie unikodą,
paspauskite http://unicode.org
nuorodą. Čia jūs rasite informaciją apie
unikodo standartus, kaip gauti kietą standarto kopiją ir
galėsite tapti šios organizacijos nariu.
Java palaiko C stiliaus komentarus ir prideda naują stilių, kad būtų galima automatiškai sukurti operatyvią dokumentaciją. Nesvarbu kurį komentarų stilių jūs naudojate; jie bus visi interpretuojami vienodai. Esmė ta, kad kompiliatorius nenaudos komentarų teksto formuojant vykdomosios programos komandas.
Visi C stiliaus komentarai yra tokie:
Java turi ir trečią komentavimo stilių, kuris naudojamas automatiškai dokumentuoti programą. Šiuos komentarus naudoja javadoc programa, kuri įtraukta į JDK rinkinį ir sukuria Interneto puslapį aprašantį jūsų kodą. Šio stiliaus komentarai yra įtraukiami į sukuriamą dokumentacijos Interneto puslapį. Komentarai naudojami automatinės dokumentacijos turi tokį formatą:
/** tekstas */
Kiekvienos kalbos kūrėjai susiduria su problema pagal kokias taisykles komentarai įterpinėjami vieni į kitus. Skirtingos kalbos apdoroja komentarus įvairiai ir Java šia prasme nėra išimtis. Taisyklės dirbant su Java komentarais yra tokios:
Pateiktas pavyzdys padės paaiškinti visų taisyklių prasmę. Kompiliatorius visą pavyzdžio eilutę interpretuos kaip vieną /* .. */ tipo komentarą:
/* normalūs komentarai su // /* /** simboliais viduje. Komentarai pasibaigia čia */
Kiekviena kalba turi grupę žodžių rezervuotą kompiliatoriaus panaudojimui. Šie raktiniai žodžiai negali būti naudojami kaip identifikatoriai jūsų programos. 4-1 lentelėje išvardinti raktiniai žodžiai rezervuoti Java kompiliatoriui. Pažymėti su žvaigždute žodžiai yra rezervuoti ateičiai. Kai kurie, tokie kaip konstanta, yra rezervuoti, kad programos kodo ir komentarų skaitymas neklaidintų programuotojo. Juos Java kalbos kūrėjai ateityje gali irgi įprasminti.
Java kalbos raktiniai žodžiai | ||||
---|---|---|---|---|
abstract | do | implements | package | throw |
boolean | double | import | private | throws |
break | else | *inner | protected | transient |
byte | extends | instanceof | public | try |
case | final | int | *rest | *var |
*cast | finally | interface | return | void |
catch | float | long | short | volatile |
char | for | native | static | while |
class | *future | new | super | ** strictfp |
*const | *generic | null*** | switch | |
continue | *goto | operator | synchronized | |
default | if | *outer | this | |
Kintamasis gali būti vieno iš keturių rūšių duomenų tipo: klasės, interfeiso, masyvo ir pirminio tipo. Kompiliavimo metu kompiliatorius klasifikuoja kiekvieną kintamąjį kaip arba nuorodą arba pirminį. Klasėms, interfeisams ir masyvams išsaugoti naudojamos nuorodos. Pirminiai tipai yra duomenų tipai į kurį įtraukiami sveikieji skaičiai, slankaus kablelio skaičiai, simboliai ir loginiai. Pirminiai duomenų tipai yra išsaugojami tiesiogiai; jų užimamas dydis atmintyje yra apibrėžtas ir niekada nesikeičia.
Pirminiai tipai yra pagrindiniai kiekvienoje programavimo kalboje. Apie juos kompiliatorius žino iš anksto; kiekvienas vartotojo apibrėžtas tipas gali būti išskaidytas į pirminius tipus. Jie yra darbiniai blokai kurie yra naudojami net paprasčiausioje programoje. Su kiekvienu pirminiu tipu susipažinsime plačiau, kad vėliau galėtume juos naudoti savo Java programose.
Java kūrėjai iš anksto apibrėžė kiekvieno pirminio duomenų tipo dydį.
Kiekvieno pirminio tipo užimama atmintyje vieta nepriklauso nuo mašinos
ir todėl, skirtingai nuo C ir C++, Javos atveju pirminiam dydžiui
nereikalinga size funkcija. Tai yra viena iš priežasčių, kodėl
Java kodai yra pilnai perkeliami į skirtingų platformų kompiuterius.
Sveikasis skaičius žymi visus netrupmeninius skaičius. Mažiausias sveikojo skaičiaus pokytis yra lygus 1 arba -1. Dauguma skaičiavimų atliekami naudojant sveikuosius skaičius. Sveikojo skaičiaus skirtingus tipus galima atskirti pagal jų užimamą ilgį. Jų ilgis kinta nuo 8 iki 64 bitų. Javoje nėra sveikųjų skaičių tipo, kuris būtų be ženklo (unsigned). tipai jūs ne įprastai naudoja. 4-2 lentelėje pateikiamos kiekvieno sveikojo skaičiaus tipo charakteristikos.
Vardas | Dydis (bitų) | Minimumas | Maksimumas | Pavyzdys |
---|---|---|---|---|
byte | 8 | -128 | 127 | 16,-16 |
short | 16 | -32768 | 32767 | 99, -99 |
int | 32 | -2147483648 | 2147483648 | 99999, -99999 |
long | 64 | -922372036854775808 | 922372036854775807 | 100000000000 |
Sveikojo skaičiaus simboliai gali būti išreikšti programoje vienu iš trijų pagrindu: jūs gali įvest jį pagrindu 10 (dešimtainiu), pagrindu 16 (šešioliktainiu) arba pagrindu 8 (aštuntainiu). Visi skaičiai yra laikomi dešimtainiais jei nenurodyta kokiu pagrindu jie užrašyti. Visi tiesiogiai užrašyti programoje skaičiai yra paverčiami tipu int . Jūs galite pakeisti int tipą su cast arba pabaigti skaičių raide L , kuri nurodo kompiliatoriui, kad šis skaičius yra "long" tipo.
Šešioliktainis skaitmuo gali kisti diapazone nuo 0 iki 15. Raidės nuo A iki F išreiškia skaitmenis nuo 10 iki 15. Šešioliktainiai skaičiai naudingi tuo atveju, kai jums reikalingas skaičiaus dvejetainis kodas. Šia forma užrašyti dideli skaičiai užima mažiau
Pavyzdžiui užrašykime skaičių 32767 šešioliktaine forma. Jis yra didžiausia galima short reikšmė. Jo šešioliktainis užrašas yra ox7FFF. Taigi, kiekvienas šešioliktainis skaičius pradedamas ox; čia didžiosios/mažosios raidės nesvarbu.
Aštuntainio skaičiaus požymis yra vedantysis nulis. To paties dešimtainio 32767 aštuntainis užrašas būtų toks: 077777 . Vedantysis nulis pasako kompiliatoriui, kad toliau užrašytas skaičius yra išreikštas aštuntainia forma.
Sveikieji skaičiai pasižymi taip vadinamas cikliško perkėlimo savybe. Jeigu jūs mėginsite vienetu arba padidinti arba sumažinti sveikąjį skaičių, kuriam išreikšti neužtenka tam tipui skirtos atminties, skaičiaus reikšmė bus pakeista cikliškai. Paimkime byte tipo skaičių, kurio reikšmė yra 127. Jeigu jūs padidinsite vienetu šitą skaičių, jo reikšmė taps lygi -128. Tai yra skaičius tampa iš didžiausio teigiamo mažiausiu neigiamu byte tipo skaičiumi. Atvirkščiai, jei būtų iš byte tipo skaičiaus lygaus -128 atimtas 1, jis virstų 127. Pasirenkant sveikojo skaičiaus tipą, turite įvertinti koks bus jo kitimo diapazonas ir pagal tai išsirinkti konkretų tipą.
Java realizuoja viengubo ir dvigubo tikslumas slankaus kablelio skaičius, kuriems teisinga nurodyta IEEE standarte binarinių slankaus kablelio skaičių aritmetika. Šios dvi formos yra atitinkamai: float ir double tipo. float yra 32 bitų viengubo tikslumo slankaus kablelio skaičius. double tipas yra 64 bitų ilgio ir naudojamas aprašyti skaičius dvigubu tikslumu.
Slankaus kablelio skaičiai gali saugoti specialiai apibrėžtas reikšmes: neigiama begalybė, neigiamas nulis, teigiamas nulis, teigiama begalybė ir ne skaičius (NaN). Kadangi šios reikšmės yra apibrėžtos Java kalboje, jūs galite jas naudoti savo kode. Kai atsitinka speciali situacija - nulis padalintas iš nulio, rezultatas bus gautas kaip NaN. Tai yra naudinga programuojant, nes bet kuriuo atveju galima atlikti dalybos veiksmą.
Visi tiesiogiai parašyti slankaus kablelio laikomi double tipo, jei jų tipas nenurodytas. Kad skaičius būtų 32 bitų float , jį reikia parašyti su f raide pabaigoje. Taip kompiliatoriui yra pasakoma, kad šitas skaičiusbūtų išsaugotas kaip float . Kadangi Java tikrina tipus priskyrimo metu, jūs bus turite suprasti kokio tipo skaičių priskiriate slankaus kablelio kintamiesiems.
Pateikto kodo fragmentas generuos kompiliatoriaus klaidą, nes priekirimo metu bus aptikta, kad tipai nesiderina:
float Num = 1.0;
Kadangi visi tiesiogiai užrašyti slankaus kablelio skaičiai yra laikomi double tipo skaičias, jums reiks apibrėžti kad 1.0 yra float parašant f po 1.0, t.y. 1.0f. Pataisytas kodas atrodytų taip :
float Num = 1.0f;
Atkreipkite dėmesį, kad slankaus kablelio skaičius naudoti programos
vykdymo valdymui kontroliuoti yra rizikinga.
Du slankaus kablelio skaičiai gali būti praginos metu palaikyti lygiais,
jei daug jų dešimtainių ženklų sutampa, nors matematine prasme
jūs užrašėte skirtingus skaičius. Naudojant slankaus kablelio skaičius
ciklo skaitliuko kintamajam ciklo operatorius lėčiau vykdomas
ir gali atsirasti sunkiai prognozuojamų praginos rezultatų.
Pvz. sunku iš prognozuoti ar 0.333333333333333 sutaps su 0.3333333333333333
ar ne.
Simboliams saugoti naudojamas unikodo standartas (žr. šito skyriaus dalį "Identifikatoriai ir unikodas" ). Kiekvienas simbolis išsaugojamas 16 bitų numeriu. Unikodas leidžia jums saugoti daugelį skirtingų neatspausdinamų arba užsienio kalbos simbolių. Kad apibrėžti simbolį tiesiogiai, jūs galite naudoti arba normalius simbolius arba unikodo perėjimo (escape) sekas. Bet kuriu atveju, jums reikės patalpinti reikšmę tarp poros viengubų kabučių.
Unikodas perėjimo (escape) seka gali būti nurodyta naudojant du metodus. Pirmaa būdas bus pažįstamas C/C++ programuotojams. 4-3 lentelėje iliustruojamos Jūs galite perėjimo (escape) į unikodą sekos.
Perėjimo (escape) sekos | Paskirtis | Unikodas |
---|---|---|
\b | Tarpas | \u0008 |
\t | Horizontalus tarpas | \u0009 |
\n | Eilutės perdavimas | \u000a |
\f | Eilutės perstūma | \u000c |
\r | Karietėlė | \u000d |
\" | Dviguba kabutė | \u0022 |
\' | Vienguba kabutė | \u0027 |
\\ | Pasviras brūkšnys | \u005c |
Jūs taip pat galite pereiti į unikodo sekas surenkant \u pratęstas keturženkliais šešioliktainiais skaičiais, kurie nurodo specifinį jums reikalingą simbolį. Skaičius gali kisti diapazone nuo \u0000 iki \u00ff. Keletas unikodo simbolių pavyzdžių:
Loginiai kintamieji gali turėti tik dvi reikšmes: true arba false . Skirtingai nuo C, jūs negalite priskirti sveikuosius skaičius loginiams kintamiesiems. Kad generuoti atitinkamą loginę reikšmę, jūs galite palyginti sveikąjį skaičių su 0. Konvertuojant sveikąjė skaičių i į loginį, jūs galite naudoti tokias Java komandas:
int i; boolean b; b = (i != 0);
Čia mes yra panaudojome nelygus operatorių, kad patikrinti ar i lygus nuliui. Skliausteliai reikalingi, kad išraiška būtš skaičiuojama teisinga tvarka.
Loginiai kintamieji yra svarbi Java ir kitų kalbų koncepcija.
Kai ir kitos kalbos, jie naudojami ciklams valdyti.
Java ciklai jums bus lengvai suprantami, jei žinote jų sintaksę C kalboje.
Pirminių duomenų tipų konvertavimas
Konvertavimas tarp dviejų pirminių duomenų tipų yra bendra praktika. Sunkumas konvertuojant vieną kintamąjį į kitą yra tame, kad jūs turite suprasti savo sprendimo galimas pasekmes. Je esate neatidus, galite prarasti dalį informacijos ir gauti netikėtą rezultatą.
Java visuomet tikrina tipus. Kompiliatorius automatiškai nekonvertuoja vieno tipo į kitą. Jums reikia tiksliai nurodyti, kad norite pervesti vieno tipo kintamąjį į kitą. Šis mechanizmas vadinamas tipo pakeitipu (angl. cast). Jis pasako kompiliatoriui konvertuoti iš vieno tipo į kitą. Kitose kalbose yra liberasnės skirtingų tipų kintamųjų priskyrimo taisyklės. Java priverčia programuotoją keičiant tipą sąmoningai pasakyti: "Aš suprantu, kad naudodamas šį tipo pakeitimą galiu prarasti dalį informacijos, bet mano programos atveju tai neturėtų pakenkti".
Java tipų pakeitimas nurodomas analogiškai kaip ir C/C++ kalboje. Jūs užrašote norimą tipą skliausteliuse prieš keičiamą kintamąjį. Jeigu tipo konvertavimas palaikomas, rezultatas yra apskaičiuojamas ir atliekamas priskyrimas. Tarkime jūs turite du kintamuosius: shortVar ir intVar (shortVar tipo short ; intVar tipo int). Šiuo atveju galimi du tipų konvertavimo variantai:
short shortVar=0; int intVar=0; intVar = shortVar; shortVar = intVar; // nesuderinami priskyrimo tipai. // Šioje vietoje bus pažymėta kompiliavimo klaida
Kompiliuojant šitą kodą gausime kompiliavimo klaidą, nes priskyrimas shortVar = intVar duos nesuderinamų tipų kintamųjų priskyrimo klaidą. Jūs mėginate priskirti didesnio kitimo diapazono kintamąjį (intVar, tipas int ) mažesnio kitimo diapazono (shortVar, tipas short ). Toks tipo konvertavimas vadinamas siaurinimo konvertavimu. Siaurinimo atveju jūs galite prarasti dalį informacijos. Tiesą sakant jūs ją prarandate visuomet; nors tuo atveju, kai visi prarandami bitai yra nuliniai, laikoma, kad siaurinimo nuostolių nebuvo. Pavyzdžiui, konvertuojant iš long (64 bitai) į int (32 bitai), jūs turite padaryti protingą sprendimą, kad būtų nenukenčiama dėl galimo informacijos praradimo. Jeigu jūs užtikrinti kad long reikšmės neišeis iš int kitimo diapazono, galite naudoti tipo pakeitimą (cast); kitu atveju, jums vertėtų bent atspausdinti perspėjimą vartotojui, kad dalis informacijos priskyrimo metu galėjo dingo.
Perrašykime naujai anksčiau parašytą kodą:
short shortVar=0; int intVar=0; intVar = shortVar; shortVar = (short) intVar;
Kompiliatorius dabar leis jums padaryti paskutinį priskyrimą. Sveikasis skaičius intVar bus būti konvertuotas į short praleidžiant aukštesniuosius bitus ir išsaugojant skaičius ženklo skiltį. case operatorius pasako, kad norite iš 32 bitų sveikojo skaičiaus pereiti 16 bitų short skaičių panaikinant vyriausiuosius 16 bitų.
4-4 lentelė 4-4 parodyti galimi pirminių tipų konvertavimai. C reiškia, kad jūs keičiant tipą turite naudoti (cast) operatorių; jei to napadarysite - gausite kompiliavimo klaidą. L pažymi, kad tipų konvertavimo metu yra galimas dalinis informacijos praradimas. X žymi, kad šios tipų poros konvertavimas Java kalboje neleidžiamas.
Pradinis tipas | Paskirties tipas | |||||||
---|---|---|---|---|---|---|---|---|
byte | short | int | long | float | double | char | boolean | |
byte | C | X | ||||||
short | C, L | C | X | |||||
int | C, L | C, L | C, L | X | ||||
long | C, L | C, L | C, L | C, L | C | C, L | X | |
float | C, L | C, L | C, L | C, L | C, L | X | ||
double | C, L | C, L | C, L | C, L | C, L | C, L | X | |
char | C, L | C | C | C | C | C | C | X |
boolean | X | X | X | X | X | X | X | |
Slankaus kablelio į sveikąjį skaičių
Kada konvertuojama iš slankaus kablelio skaičiaus į kiekvieną sveikojo skaičiaus tipą, jūs visuomet prarandate visą trupmeninę informaciją. Java atmeta trupmeninę reikšmę apvalindama skaičių link nulio. Gautas sveikasis skaičius gali neteisingai atspindėti ir sveikąją dalį, jei konvertuojamasis slankaus kablelio skaičius buvo pakankamai didelis.
double tipo į float konvertavimas
Konvertavimas iš double tipo į float bus atliekamas pagal IEEE 754 nustatytą standartą. Reikšmės kurios yra per didelės kad tilpti į float diapazoną bus pakeistos NaN (ne skaičius) reikšme.
Loginis į arba iš bet kurio tipo
Konvertavimas į arba iš loginio kintamojo tipo į kitus pirminius tipus Java kalboje neleidžiamas. Jeigu jūs norite konvertuoti iš sveikojo skaičiaus į loginį arba loginį į tekstą, jūs turite rankiniu būdu konvertuoti šias reikšmes. Pavyzdžiui, galite naudoti tokį kodą:
boolean bool; int i=15; String st=null; if (i == 0) bool = false; else bool = true; if (bool) st = "true"; else st = "false";
Informaciją apie nuorodų duomenų tipų ( class,
interface, array ) konvertavimą rasite šio skyriaus skyrelyje
"Objektai".
Java kintamasis gali būti pirminio tipo, objektas arba interfeisas. Kintamąjį galima paskelbti bet kurioje programos dalyje. Kiekviena paskelbimo komanda gali būti pratęsta pradinės reikšmės priskyrimo operatoriumi.
Iš anksčiau pateiktų pavyzdžių matyti, kad kintamieji paskelbiami ir jiems priskiriamos pradinės reikšmės gana paprastai. Pateiksime dar keletą pavyzdėlių:
int i=42; String it="Hello World"; float pi=3.14f; boolean cont;
Dar kartą pabrėšime, kad kintamasis gali būti paskelbtas bet kurioje
programos vietoje; paskelbimo operatorių galite pratęsti pradinės reikšmės
priskyrimu, bet tai nėra būtina.
Kiekvienas paskelbtas kintamasis turi savo gyvavimo trukmę, arba kontekstą, kuris priklauso nuo to, kurioje vietoje kintamasis yra paskelbtas. Kada jūs Java programos kodo dalį apgaubiate riestiniais skliaustais {}, jūs apibrėžiate naują galiojimo lygį. Galiojimo lygis apibrėžia kada reikia kintamąjį atlaisvinti ir kur šis yra pasiekiamas. Kintamieji pasiekiami tik tuo atveju, jeigu jie buvo paskelbti einamojo konteksto bloke arba juos paskelbė vienas jų tėvų.
Kada išeinama iš galiojimo lygio, kiekvienas kintamasis, kuris buvo paskelbtas to lygio bloke tampa nepasiekiamas. Jeigu kintamasis buvo pirminio tipo, jis nustoja galioti iš karto. Kitaip yra su nuorodų tipų kintamaisiais. Nuorodos atveju šiukšlių surinkėjas nusprendžia kada kintamąjį iš tikrųjų galima atlaisvinti. Taip bus tik tada, kai daugiai nebus nuorodos į tą kintamąjį. Taigi, pirminių duomenų tipų kintamieji atlaisvinami visada, kai išeinama iš konteksto bloko. Analogišku atveju nuorodos kintamasis gali būti atlaisvintas arba ne, tai sprendžia šiukšlių surinkėjas.
Galiojimo taisykles lengviau suprasti jeigu programos blokus įsivaizduoti medžio šakomis. Kiekvienas naujas blokas sukuria naują medžio šaką. Kuo didesnis bloko lygis, tuo aukštesnėje medžio vietoje jis bus patalpintas. Pateiksime programos kodo pavyzdį ir jos blokų galiojimo medį:
class foo { int cnt; public void test1() { int num; } public void test2() { for(int cnt=0; cnt < 5; cnt++) { System.out.println(cnt); } } }
4-1 paveikslėlis iliustruoja šios klasės blokų galiojimo pirmumo medį.
4-1 paveikslėlis. Galiojimas medis.
Pastebėkime, kad kiekvienas naujas blokas sukuria naują galiojimo šaką. Medis prasideda nuo paketo (package ) lygio, kuriam priklauso visos klasės ir interfeisai. Kitą lygį sukuria klasės kintamieji ir klasės metodų vardai. Kiekvienas klasės metodas pradeda jų pačių galiojimo lygį; jų lokalūs kintamieji yra apibrėžti tik čia. Pastebėkime, kad daliniu atveju metodas test2 neturi lokalių kintamųjų paskelbtų pirmame kontekste, bet cikle sukuriamas naujas kontekstas ir jame yra apibrėžtas kintamasis vadinamas cnt. Šitas kintamasis užgožia anksčiau aukštesniame klasės lygyje paskelbtą cnt.
Ne C programuotojams for ciklas gali būti naujas. Plačiau apie ciklus kalbėsime "Programos praginos eigos valdymo" skyrelyje.
Turint daugelį galiojimo lygių atsiranda galimybė maskuoti arba užgožti kitus kintamuosius. Sakykime jūs sukūrėte klasės kintamąjį cnt. Po to klasės metode jūs taip pat sukūrėte kintamąjį cnt. Naujas kintamasis užgožtų arba paslėptų ankstesniojo klasės kintamojo cnt egzistavimą. Kiekvienas kreipimasis į cnt metodo viduje duotų naujojo cnt reikšmę. Kad pasinaudoti anksčiau apibrėžtu klasės kintamuoju cnt metodo viduje turėtume parašyti taip:
this.cnt = 4;
Yra bendra taisyklė vengti kintamųjų užgožimo. Tai suprantama,
nes užgožiamų kintamųjų panaudojimas padaro programos kodą sunkiai skaitomu.
Kintamųjų vardai turi prasidėti raide. Jis gali būti be galo ilgas ir susidaryti iš raidžių, skaitmenų ir visų skyrybos simbolių išskyrus taško. Kintamieji negali kartoti kitų to paties galiojimo lygio identifikatorių. Tai reiškia, kad negali turėti kintamųjų su tuo pačiu vardu, kuris būtų:
Jeigu jūs naudojate unikodo simbolius (kad palaikyti ne anglų kalbą, pvz. lietuvių), tuomet jums reikia suprasti kaip Java atlieka simbolių palyginimą. Vardas (identifikatorius) bus lygus kitam, jeigu šis turi tiksliai tą pačių unikodo simbolių seką. Tai reiškia, kad lotynų didžioji A (\u0041) skirsis nuo graikų didžiosios A (\u0391). Taip pat reikia atsiminti, kad Java kalboje yra skiriamos didžiosios ir mažosios raidės.
Java palaiko daug operacijų. Operatoriaus simbolis naudojamas vykdant operacijas su vienu ir daugiau kintamųjų. Tipiniai operatorių pavyzdžiai yra plius (+), minus (-), lygu (=). Operatoriai yra klasifikuojami pagal naudojamų argumentų skaičių. Kai kurie operatoriai (pvz., kaip minus) turi skirtingas reikšmes priklausomai nuo to ar jis turi vieną ar du operandus.
. | [] | () | ||
++ | -- | ! | ~ | instanceof |
* | / | % | ||
+ | - | |||
<< | >> | >>> | ||
< | > | <= | >= | |
== | != | |||
& | ||||
^ | ||||
| | ||||
&& | ||||
|| | ||||
?: | ||||
= | Op= | |||
, | ||||
Operatorius op= sutrumpintai žymi visas galimas operacijas
su toliau einančiu = ženklu.
Pavyzdžiui, +=, *=, |= ir taip toliau.
Išraiška yra operatorių ir operandų kombinacija. Išraiškos reikšmei apskaičiuoti naudojamos operacijų eiliškumo taisyklės. Operacija turinti eiliškumo pirmenybę prieš kitą bus vykdoma pirma. Tipinis pavyzdys galėtų būti dar mokykloje įsisavintas eiliškumo principas apskaičiuojant matematines išraiškas su atimties, sudėties ir daugybos bei dalybos operacijomis. Pavyzdžiui, x = 2+4*3 rezultatas bus x=14, bet ne 18.
Sudėtingų išraiškų atveju geriau tiesiog panaudoti skliaustelius, kad nesusipainioti su operacijų vykdymo tvarka. Taip apsaugosite ne tik save nuo klaidų, bet ir padidinsite savo programoms suprantamumą kitiems programuotojams. 4-5 lentelėje nurodytas operacijų eiliškumas. Operacijos kurios pasirodo toje pačioje eilutėje yra lygaus eiliškumo ir bus apskaičiuojamos iš kairės į dešinę.
Operacijos su skaičiais patenka į dvi kategorijos: unarinės operacijos, kurios dirba į vienu kintamuoju ir binarinės operacijos, dirbančios du dviem skaičiais. Toliau binarinius operatorius galime skirstyti į grąžinančius skaitinį rezultatą ir palyginimo operatorius, grąžinančius loginę reikšmę.
Operacijos rezultatas visuomet bus to paties tipo kaip didžiausio operando tipas. Tarkime sudedame du skaičius - vienas short , kitas long tipo. Sudėties rezultatas bus long . 4-6 lentelėje aprašyti analogiški atvejai su kitais pirminiais tipais. Atkreipkite dėmesį, kad mažiausiais operacijų su sveikaisiais skaičiais grįžties rezultatas yra int. Pradžioje paanalizuosime unarines operacijas.
1 tipas | 2 tipas | Rezultatas |
---|---|---|
byte | byte | int |
byte | short | int |
byte | int | int |
byte | long | long |
short | short | int |
short | int | int |
short | long | long |
int | int | int |
int | long | long |
int | float | float |
int | double | double |
float | float | float |
float | double | double |
Unarinės operacijos reikalauja vieno operando - parametro. Operacija atliekama ir rezultatas patalpinamas operande. Rezultato tipas bus visuomet tas pats kaip ir pradinio tipo, nes čia nėra galimybės prarasti tikslumą arba dydį. 4-7 lentelėje išvardinti Java unariniai operatoriai.
Operacija | Aprašymas |
---|---|
- | Unarinis minus |
+ | Unarinis plius |
~ | Bitinis papildinys |
++ | Padidinimas vienetu |
-- | Sumažinimas vienetu |
Kai kurios galimos unarinės išraiškos:
Unarinis minus ir plius
Unarinis minus operatorius (-) naudojamas pakeisti skaičiaus ženklą. Neigiamas skaičius tampa teigiamu, o teigiamas skaičius tampa neigiamu. Unarinis plius operatorius iš tikrųjų neatlieka jokio darbo. Jis yra įvestas dėl simetriškumo.
Sveikojo skaičiaus ženklo pakeitimas gali būti interpretuojamas atėmimu iš nulio. Tai tiesa dėl visų bet ne didžiausio neigiamo skaičiaus; unarinis minus nekeičia šių skaičių. Priežastis yra ta, kad neigiamų skaičių yra vienu daugiau ir nėra kaip didžiausią neigiamą pakeisti teigiamu skaičiumi. Kad tai iliustruoti, pažiūrėkime kodo pavyzdį, kurio darbo rezultatas bus netikėtas: -128.
byte i=-128; System.out.println(-i);
Dirbant su slankaus kablelio skaičiai atsiranda keletas specialių atvejų. Skaičius su reikšmė NaN bus toks pat NaN ir po ženklo pakeitimo. Teigiamas ir neigiamas nuliai, kaip ir kitų skaičių atveju, pakeis ženklą. Tas pats teisinga ir teigiamai ir neigiamai begalybei.
Bitinis papildinys
Bitinio papildinio operacija atliekama su sveikojo skaičiaus tipo kintamaisiais. Jis sveikojo skaičiaus bitus su 1 pakeičia 0 ir atvirkščiai. Jei skaičius buvo x, tai ~x sutampa su (-x)-1. Kalbose, kuriose naudojami skaičiai be ženklo bitų papildymo operaciją duoda kitą rezultatą. Pavyzdžiui Paskalio byte atveju, 0 papildinys būtų 255; Javoje gausite, kad ~0 rezultatas yra -1.
Padidinimas vienetu ir sumažinimas vienetu
Padidinimo vienetu (++) ir sumažinimo vienetu (--) operatoriai yra sutrumpintas būdas pridėti 1 arba atimti 1. Jie gali būti parašyti arba prieš arba po kintamojo. Patalpinus ++ po operando, pirma apskaičiuojama išraiška ir po to operandas padidinamas vienetu. Patalpinus ++ prieš operandą, pirma operandas padidinamas vienetu ir po to apskaičiuojama išraiška. Pailiustruosime tai pavyzdžiu.
int i=0; int j=0; System.out.println(++i); System.out.println(j++);
Šios programos darbo rezultatas bus 1 ir 0. Pirma spausdinimo komanda pirma padidins i tuomet jį atspausdins. Kitu atveju kintamasis j bus atspausdintas ir tuomet padidintas vienetu. Pastebėkime kad abiem atvejais i ir j reikšmės pabaigoje bus lygios 1.
Binariniai operatoriai naudoja du operandus, atlieka veiksmą ir grąžina rezultatą. Rezultatas turi tą patį tipą kaip didžiausias operandas. Sudėdami byte ir int gausime rezultatą int tipo. Operacijų rezultatas neįtakoja kintamųjų (operandų) reikšmes. Binarinės operacijos skaidomos į dvi grupes: pirmoji grąžina rezultate skaičiaus reikšmę, o antroji - loginę reikšmę. 4-8 lentelėje išvardintos binarinės operacijos, kurios grąžina skaičių.
Operacija | Aprašymas |
---|---|
+ | Sudėtis |
- | Atimtis |
* | Daugyba |
/ | Dalyba |
% | Modulis |
& | Bitinis AND |
| | Bitinis OR |
^ | Bitinis XOR |
<< | Su ženklu poslinkis į kairę |
>> | Su ženklu poslinkis į dešinę |
>>> | Be ženklo poslinkis į dešinę |
Op= | Kombinacija priskyrimas ir operacija |
Adityvios operacijos
Adityvios operacijos yra + ir -. Jeigu bent vienas operandas yra slankaus kablelio skaičius, jie bus abudu konvertuoti į slankaus kablelio skaičius. Kiekvieno tipo sveikasis skaičius išskyrus long bus konvertuojamas į int . Tai reiškia, kad adityvus operatorius niekada negrąžins byte arba short reikšmės. Kad priskirti rezultatą byte arba short tipo kintamajam, jūs turėsite panaudoti tipo pakeitimo (cast) operatorių. Atikdama slankaus kablelio skaičių sudėties ir atimties operacijas, Java laikosi IEEE taisyklių. Specialiais atvejais, pavyzdžiui sudedant du NaN slankaus kablelio skaičius, reikia pažiūrėti į kalbos specifikaciją, kad žinoti kaip tokie atvejai traktuojami.
Dauginimo operatoriai
Dauginimo operatoriai yra *, / ir %. Jie konvertuoja operandus panašiu būdu kaip ir adityvieji operatoriai. Operacijos su sveikaisiais skaičiais yra asociatyvios, išskyrus operacijas su slankaus kablelio skaičiais. Pavyzdžiui, įsivaizduokime mes turime du slankaus kablelio skaičius. Vienas yra teigiamas 1, kitas didžiausias išreiškiamas teigiamas skaičius:
float vienas = 1f; float max = 2^24e104;
Duotas kodas negrąžintų true :
vienas + max - vienas == max - vienas + vienas
Pirmu atveju mes pridedame 1 prie didžiausio išreiškiamo float . Čia gausime perpildymą ir rezultatas bus teigiama begalybė. Atimant 1 iš begalybės gausime begalybę; taigi kairės pusės išraiškos rezultatas bus teigiama begalybė. Dešinės pusės išraiškoje atimamas 1 iš max , tuomet pridedamas 1 ir gauname reikšmę max .
Liekana (%) arba dalyba moduliu apibrėžiama taip, kad (a/b) * b + (a%b) = a. Šita operacija daro tai ko jūs tikitės, išskyrus tai, kad ji duoda teigiamą rezultatą, kai daliklis teigiamas ir neigiamą rezultatą kitu atveju. Rezultato absoliutinė reikšmė visuomet yra mažesnė už daliklį.
Pavyzdys su modulio operatoriumi:
int i=10; int j=4; int k=-4; System.out.println(i % j); // = 2 System.out.println(i % k); // = -2
Java dalybos liekanos operatorius skirtingai elgiasi nei nurodyta
IEEE 754. Jeigu jūs norite panaudoti IEEE apibrėžimą,
galite panaudoti matematinę biblioteką math.IEEEremainder.
Bitiniai operatoriai
Bitiniai operatoriai yra naudojami, kai reikia atlikti operacijas su skaičiaus bitine išraiška. Jos turi prasmę tik dirbant su sveikaisiais skaičiais. Slankaus kablelio skaičių bitai sunkiai interpretuojami, todėl bitinis operacijos čia neturi aiškios prasmės. Bitiniai operatoriai ir (&) , arba (|) ir xor (^) naudojami patikrinti individualius sveikojo skaičiaus bitus.
Tarkime mes naudojame kiekvieną byte tipo skaičiaus bitą saugoti gairelę (flag ). Mes galime saugoti aštuonias gaireles pažyminčias kiekvieną bitą. Pateiktas kodas parodo kaip galima atlikti manipuliacijas su bitais:
byte flags=0xff; // inicijuoja į 11111111 byte mask=0xfe; // trafaretas į 11111110 flags = flags & mask; // eilės 8 pozicija flags = flags | mask // išvalo 8 poziciją flags = flags ^ mask; // = 00000001
Postūmio operatoriai
Java palaiko tris postūmius : postūmį į kairę (<<), postūmį į dešinę (>>) ir be ženklo postūmį į dešinę (>>>). Visų postūmio operacijų išraiška yra postūmio operatorius ir jo dydis. Postūmio dydis turi būti sveikojo skaičiaus tipo. Jeigu jūs norite atlikti postūmį su slankaus kablelio skaičiumi, turite pakeisti jo tipą.
Postūmis su ženklu išsaugoja operando ženklą. Be ženklo dešinysis postūmis naudos pralėtimą nuliais. ( Pralėtimas nuliais reiškia kad trūkstami bitai po perstūmimo bus užpildyti nuliais. Postūmis per 0 taip pat galimas, bet jis neturi prasmės.
Naudojant postūmio operaciją mes galime greitai atlikti sveikojo skaičiaus dalybą iš 2. Dešinysis postūmis išstums paskutinį bitą, o tai ekvivalentu dalinimui iš 2. Nelyginiai skaičiai po dalijimo iš 2 yra apvalinami iki mažesnės reikšmės:
int i = 129; // 10000001 dvejetainis i = i >> 1; // dabar 1000000 arba 64
Kombinacija priskyrimas
Išraiškos, kurios rezultatą priskiria pirmajam operandui, gali naudoti sutrumpintą žymėjimą. Reikia atkreipti dėmesį kaip veikia operandai su išraiškomis, kuriose yra ++ ir -- operacijos. Šiuo atveju jos veiks kitaip, nei įprasta. Pavyzdžiui
int i = 0; i += ++i;
rezultatas bus 1. Galima galvoti, kad turėtų gautis 2. Tačiau pirma i bus iškviestas į registrą, apskaičiuota ++i, priskirta atgal i kintamajam ir naudojamas kaip kitas operandas + operatoriui. Toliau, kadangi pradinė i reikšmė buvo 0, tai rezultate gausime 1.
Santykio operatoriai
Santykio operatoriai lygina dviejų skaitinių operandų reikšmes ir grąžina loginę palyginimo rezultato reikšmę. 4-9 lentelėje aprašyti galimi Javos palyginimo operatoriai.
Operatorius | Aprašymas |
---|---|
< | Mažiau kaip |
> | Didesnis kaip |
<= | Mažiau kaip arba lygus |
>= | Didesnis kaip arba lygus |
== | Yra lygūs |
!= | Nelygūs |
Naudojant santykio operatorius dažnai daroma tipinė klaida.
Programuotojai naudoja viengubą lygybės ženklą vietoje teisingo
dvigubo lygybės ženklo. Viengubas lygybės ženklas naudojamas
priskirti reikšmę. Dvigubas lygybės ženklas naudojamas, kad
palyginti du skaičius.
Skirtingai nuo C/C++, Java pastebės tokias klaidas,
bet geriau jų visai nedaryti.
Loginiai operatoriai
Loginės operacijos yra labai panašios į skaičių palyginamo operacijas. Visos loginės operacijos grąžina loginę reikšmę: true arba false. 4-10 lentelėje pateiktas loginių operacijų sąrašas.
Operatorius | Aprašymas |
---|---|
! | Neiginys |
& | Loginis AND |
| | Loginis OR |
^ | Loginis XOR |
&& | Sąlyginis AND |
|| | Sąlyginis OR |
== | Lygus |
!= | Nelygus |
Op= | Kombinacija priskyrimas ir operatorius |
?: | Sąlyginis operatorius |
Sąlygos operatorius yra vienintelis Java kalbos operatorius naudojantis tris operandus. Operatoriaus formatas yra a?b:c. Išraiška a yra apskaičiuojama ir gaunamas loginis rezultatas. Jeigu jis true , tuomet grąžinamas b , kitu atveju - c. Pažiūrėkime iliustraciją:
int i; boolean cont=false; // Įprasta if komanda if (cont) i=5; else i=6; // Naudojant sutrumpinimą: i = (cont?5:6);
Kodas priskiria i arba 5 arba 6 priklausomai nuo loginio kintamojo cont reikšmės. Kai cont yra true ,i priskiriama 5; kai jis false , i priskiriama 6. Sąlyginis sutrumpintas operatorius atlieka šį priskyrimą trumpesniu būdu.
Operacijos su simboliais
Nėra nei vienos operacijos, kuri naudotų simbolius ir grąžintų simboliaus tipo rezultatą. Dauguma operatorių grąžins sveikąjį skaičių. Jeigu jūs norite, kad operacijos rezultatas būtų simbolis, turite nurodyti tipo pakeitimo operatorių (char). Kada simbolis yra naudojamas operandu, jis yra pakeičiamas sveikuoju skaičiumi. Tokio pakeitimo metu informacija neprarandama. Tarkime mes norime konvertuoti simbolį - raidę iš didžiosios į mažąją. A simbolio sveikoji reikšmė yra 98 ir ASCII ir unikode, o mažosios a - 65. Jeigu mes iš didžiosios raidės ir atimsime mažąją, gausime reikšmę, kurią galėsime panaudoti ir kitų raidžių konvertavimui. Tai iliustruosime pavyzdžiu:
char c='B'; c = (char) (c - ('A' - 'a'));
Su Java objektais palaikomos tokios operacijos: =, ==, != ir instanceof . Pavyzdžiui sudėti du objektus negalima, nes bendru atveju neaišku koks turėtų būti šios operacijos turinys. Vienintelė išimtis yra eilučių atveju; tuomet ši operacija reiškia eilučių apjungimą.
Priskyrimo operatorius (=) naudojamas priskirti objekto rodyklę nurodytam kintamajam. Tai nesukuria objekto kopijos. Taip yra gaunamas kintamasis kitu vardu, tačiau jis yra tik sinonimas nuorodos, kurioje yra saugojamas objektas. Kai visi kintamieji neteks savo galiojimo lauko, objektas atlaisvinamas. Pasižiūrėkime į pavyzdį:
foo test = new foo(); foo test2 = null; test2 = test;
Šis kodas iliustruoja objektų priskyrimą. Pirma eilutė sukuria naują foo egzempliorių. Antra eilutė test2 objektui priskirią specialiąją tuščio objekto reikšmę. Kreipimasis į test2 dabar būtų negalimas ir gautume nullPointerException klaidos pranešimą. Paskutinis operatorius sutapatina test ir test2. Dabar jau abudu kintamuosius galima naudoti, tačiau jie nereiškia skirtingus objektus, nes new foo() buvo panaudotas tik vieną kartą.
Objektai palaiko dvi palyginimo operacijas: lygus operaciją (==) ir nelygus operaciją (!=). Šios operacijos tikrina ar objektų kintamieji yra nuorodos į tą pačią atminties vietą. Du objektai turintys nuorodų kintamuosius į skirtinas vietas atmintyje bus visuomet nelygūs nepriklausomai nuo to ar visi jų metodai ir kintamieji yra vienodi ar ne. Pateiksime tokios situacijos pavyzdį:
foo testas = new foo(); foo test2 = new foo(); foo test3 = testas;
Naudojant šiuos priskyrimus, mes galime su nurodytais kintamaisiais sukurti lygybės santykių lentelę. 4-11 lentelė iliustruoja kokie objektai yra lygūs ir kokie - ne.
testas | test2 | test3 | |
---|---|---|---|
testas | == | != | == |
test2 | != | == | != |
test3 | == | != | == |
instanceof ( egzemplioriaus tipo ) operatorius naudojamas nustatyti objekto tipą praginos metu. Jį panaudoti jums būtinai teks, jei norėsite sužinoti kokio tipo tapo objektas programos praginos metu. Tarkime turite shape klasės tipo kintamąjį. Tegul shape turi poklasę polygonShape ir jūs dirbate su kintamuoju, kuris pradžioje buvo paskelbtas shape tipo. Kaip jums sužinoti, ar praginos eigoje jis netapo polygonShape tipo? Pateiktas kodo fragmentas iliustruoja tokios problemos sprendimą.
shape shapeHolder; if (shapeHolder instanceof polygonShape) { polygonShape polygon = (polygonShape) shapeHolder; // darome ką nors su polygon }
Shape yra bendros formos klasė. Jeigu kintamasis shapeHolder yra specifinio tipo polygonShape, tai galime atlikti specifines šiam tipui operacijas. Kad galėtume dirbti su polygonShape tipu, mes susikurdami polygon kintamąjį apribojame kintamąjį shape iki polygonShape tipo.
Mes jau minėjome, kad "Strings " yra Java klasė turinti hibridinių bruožų būdingų pirminiam tipui ir nuorodoms į objektus. Vartojimo prasme ji panaši į objektus, tačiau turi keletą nebūdingų nuorodoms savybių. Tenka kiek apgailestauti dėl šios išskirtinės eilučių padėties.
Mes pastebėjome, kad sumos ir skirtumo operacijos objektams neapibrėžiamos. Tačiau Java atveju eilutėms padaryta išimtis. Pamatę pirmą kartą dviejų eilučių sumą nesunkiai atspėsite kas turima omenyje šiuo atveju. Jei tas pats būtų pritaikyta kitų tipų objektams sumos turinys daugeliu atvejų būtų neakivaizdus. Todėl eilutėms ir padaryta išimtis, bet tai kiek griauna kalbos principą neapibrėžinėti sumos objektams.
Kaip ir buvo galima tikėtis, pliuso ženklas paprasčiausiai apjungia dvi eilutes. Jeigu vienas operandas yra ne eilutė, jis yra konvertuojamas į eilutės tipą ir tuomet apjungiamos eilutės. Visa tai atlieka kompiliatorius atlikdamas "+" operacijos perkrovos darbą. 4-12 lentelėje išvardintos "+" operacijos perkrovos taisyklės.
Operandas | Taisyklė |
---|---|
null kintamieji | Kiekvienas kintamieji kurios reikšmė bus null bus pakeistas eilute "null ". |
Sveikasis skaičius | Sveikasis skaičius bus konvertuotas į eilutę vaizduojančią dešimtainę skaičiaus išraišką. - ženklas pradės neigiamą skaičių ir nebus rašomi vedantieji nuliai, išskyrus 0 atvejį. |
Slankaus kablelio | Slankaus kablelio skaičiai bus konvertuojami į kompaktišką formą. Jeigu užrašo ilgis viršija 10 simbolių, jis bus užrašytas eksponentine forma. Neigiamas skaičius prasidės - ženklu. |
Simbolis | Simbolis bus konvertuotas į jai ekvivalenčią 1 simbolio ilgio eilutę. |
Loginis | Rezultatas bus arba "true" arba "false" eilutė priklausomai nuo loginio kintamojo reikšmės. |
Objektas | Objektams bus keičiamas toString() metodas. |
Po konvertavimo gausime abudu operandus eilutės tipo ir jos bus apjungiamos. Keletas iliustracinių pavyzdžių:
String foo = "Sveikas "; String bar = "Pasauli"; int i = 42; boolean cont = false; String rezultatas = null; result = foo + bar; // = "Sveikas pasauli" result = foo + i; // = "Sveikas 42" result = foo + cont; // = "Sveikas false"
Naudojimo prasme tokia "+" Java interpretacija labai patogi ir
tenka sutikti su Java autorių logika. Kokia prasmė galėtų būti "-"
operacijos, kai bent vienas operandų yra teksto eilutė? Sunku pasakyti ir
todėl Javoje tokia operacija negalima.
Dabar pakalbėkime apie == ir != operacijas. Išbandykite tokio kodo darbą:
String foo = "Sveikas"; String bar = "Sveikas"; if (foo == bar) System.out.println("Sutampa"); else System.out.println("Nesutampa");
Kodo darbo rezultatas bus "Sutampa". Taip ir tikėjotės :-). Pamėginkite dabar prognozuoti kito kodo darbo rezultatą:
class testString { String st = "Sveikas"; } class testString2 { String st = "Sveikas"; String st2 = "Sveikas"; public static void main(String Args[]) { testString testas = new testString(); testString2 test2 = new testString2(); if (test.st == test2.st2) System.out.println("Sutampa"); else System.out.println("Nesutampa"); if (test.st == test2.st) System.out.println("Sutampa"); else System.out.println("Nesutampa"); } }
Rezultatas bus daugeliui (manau, beveik visiems) netikėtas. Pirmu atveju bus atspausdinta "Sutampa", o antru - "Nesutampa". Paaiškinimas yra toks. Kompiliatorius atlieka atminties optimizavimo darbą. Todėl testString2 metode bus išskirta atminties tik vienam "Sveikas" egzemplioriui ir st ir st2 nurodys į tą pačią atminties vietą ir šiuo atveju == palyginimas duos true rezultatą.
Atkreipkite dėmesį, kad eilučių atveju == operatorius skirtas nepalyginti reikšmes, bet patikrinti ar operandai yra nuorodos į tą pačią atminties vietą. Kad palyginti eilučių visų simbolių seką, naudojamas metodas equals . Pasižiūrėkime tokio palyginimo pavyzdį.
public static void main(String Args[]) { testString Testas = new testString(); testString2 Test2 = new testString2(); if (test.st.equals(test2.st2)) System.out.println("Sutampa"); else System.out.println("Nesutampa"); if (test.st.equals(test2.st)) System.out.println("Sutampa"); else System.out.println("Nesutampa"); } }
Apie eilutes mes dar pakalbėsime šio skyriaus "Strings " skyrelyje ir kituose skyriuose.
Paketas (package ) yra organizacinė priemonė numatyta Java kalboje tvarkyti klasių grupes. Konceptualiai paketas (package ) apjungia turinčias sąsają klases ir interfeisus. Jūs jau pažįstami su paketo pavyzdžiu, būtent, java.lang paketu. Šitas paketas yra neatsiejama Java kalbos dalis. Aplikacijų interfeisų programavimo (API) klasės yra taip pat apjungiamos į paketus. Jūs taip pat turite galimybę kurti savo paketus.
Pakete saugojamas vienas arba daugiau kodo failų. Kiekviename kodo faile pačioje pradžioje (neskaitant komentarų) turi būti paskelbtas package operatorius. Kiekviename kodo faile gali būti paskelbta tik viena public tipo klasė. Kada kodo failas yra sukompiliuojamas, klasės failas yra patalpinamas kataloge kurį nurodo paketo vardas. Paketo vardas reiškia katalogo vardą, kuriame pasviri brūkšniai yra pakeisti taškais. Pavyzdžiui, jeigu mes norime sukurti paketą kataloge ventana/awt/shapes, kiekvieno paketo kodo failo pradžioje turime panaudoti tokį package apibrėžimą :
package ventana.awt.shapes;
Kai mes turime paketą (package ), kaip galima panaudoti jo klases ir interfeisus? Vienas būdų yra užrašyti klasių pilną vardą. Tegul turime realizuotą paketą (package ), kuriame yra dvi klasės: circle ir rectangle . Jeigu mes norime sukurti naują apskritimo klasės egzempliorių, galime panaudoti tokį kodą: ventana.awt.shapes.circle circ = new ventana.awt.shapes(); Klasių panaudojimas rašant jų pilnus vardus gali varginti savo gremėzdiškais pavadinimais. Javos paketų importavimo (import) komanda sprendžia šią ilgų vardų problemą. Kai jūs importuojate su import paketą, toliau galite rašyti sutrumpintus importuoto paketo klasės ir interfeisų vardus. Tegul importavome apskritimo klasę iš shapes paketo. Tuomet galėsime tiesiog rašyti paketo klasės vardą nenurodant paketo vardo.
import ventana.awt.shapes.circle; class tryShapes { public static void main(String Args[]) { circle circ = new circle(); } }
Čia pateiktas sutrumpinto priėjimo prie paketo konkrečios klasės pavyzdys. Jeigu jums Java programoje bus reikalingos kelios klasės ir interfeisai, kurie yra patalpinti tame pačiame pakete, galite naudoti sutrumpintą kelių katalogų ir vardų žymėjimą wildcard . Tokiame žymėjime žvaigždutė pakeičia visus galimus klasių ir interfeisų vardus. Pavyzdžiui naudotis visomis paketo shapes klasėmis galėsime pradėdami savo klasės kodą taip:
import wentana.awt.shapes.*;
Nemanykite, kad toks paketo importavimas padidins jūsų kodo dydį. Taip yra tik iškviečiamas paketo turinys į kompiliatoriaus simbolių lentelę, kurią kompiliatorius naudoja ieškant klases ir interfeisus į kuriuos kreipiatės savo programoje. Jūs galite naudotis ir trumpuoju ir ilguoju klasių vardų variantu. Dažniausiai praktiškai naudojamas trumpasis variantas, tačiau kartais jūs būsite priversti panaudoti ilgąjį variantą, kai atsiras tuo pačiu vardu pavadintos klasės skirtinguose paketuose, kuriuos jūs importuosite su import komanda.
Mes jau kalbėjome apie klases ankstesniuose skyriuose. Dabar mes paliesime esminius sintaksės momentus. Kalbant apie klases labai pravartu pirma įsisavinti 3 skyriaus sąvokas, kur buvo kalbama apie Java objektinį programavimą. Jei objekto sąvoka jums neaiški, kalbėti apie klases maža prasmės.
Klasė yra pagrindinis darbinis Java programos blokas. Ji sudaryta iš duomenų ir metodų. Metodai apibrėžia būdus keisti ir sąveikauti su apgaubtais klasėje duomenimis. Padarydami vieną vienetą, kuriame apjungiami ir duomenys ir būdai juos keisti, mes padidiname mūsų kodo pakartotiną panaudojamumą ir pageriname programų palaikomumą.
Java, konstruktorius yra vadinamas specialus metodas sukuriantis objektų naujus egzempliorius. Konstruktorius yra klasės metodas, kurio vardas sutampa su klasės vardu ir kuriame nenurodomas grįžties (return ) tipas. Jūs galite turėti daugelį konstruktorių, bet visi turi skirtis savo unikaliu parametrų skaičiumi ar jų parametrų tipų seka. Pateiksime klasės pavyzdį, kuriame apibrėžiama keletas konstruktorių:
class foo { foo() {...} // konstruktorius be parametrų foo(int n) {...} // kviečiant reikalaujamas vienas int parametras foo(String s) {...} // kviečiant reikalaujamas vienas eilutės tipo parametras }
Čia visi trys konstruktoriai turi skirtingą parametrų skaičių arba skiriasi parametrų tipų sekos.
Kiekviena klasė gali turėti tik vieną destruktorių. Destruktorius iškviečiamas kada objektą naikina šiukšlių surinkėjas ( garbage collector ). Taigi jūs negalite būti užtikrintas kada destruktorius bus panaudojamas. Destruktorius tinkama vieta patalpinti failų uždarymus ir čia naudinga atlaisvinti tinklo resursus. Destruktoriuje nebūtų protinga paskelbti vartotojo informacijos įvedimą arba sąveikauti su kitais objektais.
Destruktorius Javoje vadinamas finalize . Jis neturi grįžties (return ) tipo ir neturi parametrų. Mes galėtume pridėti destruktorių į savo klasę foo tokiu būdu:
class foo{ finalize() {...} // daro kai kurias resursų atlaisvinimo operacijas }
Klasės modifikatorius gali būti abstract (abstraktus) , final (nekeičiamas, neturintis vaikų) arba public (vieša). Modifikatoriai turi būti rašomi prieš klasės raktažodį. Mes galime nustatyti klasės foo modifikatorių tokiu būdu:
public final class foo{...}
public klasės gali būti panaudotos iš kitų paketų. Jeigu klasė yra ne public , ją gali panaudoti paketas kuriame klasė paskelbta. Vieno failo kode galite paskelbti tik vieną public klasę. Todėl failo kode gali būti tik viena public klasė arba interfeisas.
final modifikatorius pažymi, kad ši klasė negali būti praplėsta. Kai kuriuos Java API klasės yra paskelbtos final . Pavyzdžiui, masyvas ( Array ) ir eilutės ( Strings ) klasės yra final , nes jos yra hibridinės klasės. Kitaip tariant jos nėra klasikiniai objektai, kuriuos mokėtų pilnai palaikyti kompiliatorius ir šiuo atveju Java autoriai buvo priversti juos paskelbti final . Apskritai, reikia vengti skelbti klases final , nes tuomet jūsų klasės negali turėti poklasių. Objektiniame programavime tokia savybė nepageidautina, nes kiti negalės paveldėti jūsų klasės funkcionalumo. final modifikatorius naudingas kuriant nekintamus metodus, kurių nėra prasmės perdarinėti.
Paskelbdami klasę abstrakčia (abstract ), jūs pasakote kompiliatoriui, kad joje bus vienas arba keli abstract metodai. abstract metodas neturi kodo ir jis turi būti realizuotas vėliau poklasėse. Ji negali būti inicijuota, bet gali ir turi būti praplėsta. Kiekviena abstract klasės poklasė turi realizuoti abstrakčius metodus arba pati turi būti paskelbta abstract tipo. Abstrakčių klasių mechanizmas leidžia struktūriškai programuoti. Abstract klasė vadinamu interfeisu ; apie tai plačiau skyrelyje "Interfeisai".
extends (praplečia ) raktažodis
Paveldėjimui paskelbti naudojamas extends (praplečia) raktažodis. Kiekviena klasė gali praplėsti ne daugiau vienos klasės. Tačiau panaudojant interfeisus galima imituoti daugelio klasių paveldimumą.
Visi Java objektai turi tą patį tėvą vadinamą objektu. Jeigu jūs nenustatote objekto tėvo, jo nutylimasis tėvas yra klasė Object . Kad apibrėžti klasės tėvą, naudojamas extends (praplečia ) raktažodis. Jeigu mes turėtume klasę foo , galėtume sukurti jos poklasę bar :
class bar extends foo{...}
Poklasė paveldi klasės metodus ir kintamuosius. Jūs galite apibrėžti iš naujo arba maskuoti metodą arba kintamuąjį sukurdami metodą ar kintamąjį su tuo pačiu vardu. Kad panaudoti užmaskuotą identifikatorių, jums reikia naudoti super kintamąjį. Šis kintamasis nurodo į klasės tiesioginį tėvą. Jeigu foo turi metodą vardu test , tai jį užmaskuoti bar klasėje galėsime taip:
class bar extends foo{ void test() { super.test(); // iškviečia tėvo test metodą // ir atlieka kitus veiksmus } }
Jeigu praplečiant klases organizuosite ciklinį paveldėjimo santykį,
gausite kompiliavimo klaidą. Klasė B
negali būti A poklasė jeigu A
jau yra B poklasė.
implements (realizuoja )
Klasės gali implementuoti net kokį interfeisų skaičių. Interfeisas yra klasės kurios visi metodai yra abstraktūs (abstract ). Paskelbiant klasę implements raktažodis yra rašomas paskutiniu. Pilna klasės paskelbimo sintaksė yra tokia:
klasės_modifikatoriai class klasės_vardas extends tėvo_vardas implements interfeiso_vardas {...}
Visi elementai išskyrus class raktažodį ir klasės vardą yra nebūtini. Jeigu klasė realizuoja interfeisą, joje būtina realizuoti metodus apibrėžtus interfeise. Vienintelė šios taisyklės išimtis yra abstract klasės atvejis; šiuo atveju klasės vaikai privalo realizuoti interfeiso metodus.
Tegul turime interfeisą vadinamą shapeInterface, kuris turi du metodus - draw ir erase . Tuomet mes galėtume apibrėžti klasę vardu shape , kuri realizuotų interfeiso metodus:
class shape implements shapeInterface { void draw() {...} void erase() {...} }
Po implements galima vienai klasei nurodyti daugelio interfeisų vardus atskiriant juos kableliais. Programuotojas privalo realizuoti visus interfeisuose nurodytus metodus. Tarkime turime du interfeisus: shapeInterface ir moveableInterface. Tuomet galėtume apibrėžti klasę dragDrop, kuri realizuotų abudu šiuos interfeisus:
class dragDrop implements shapeInterface, moveableInterface {...}
Interfeisų sintaksę aptarsime vėliau skyrelyje "Interfeisai".
Apibrėždami klasės kintamuosius galite nurodyti jų modifikatorius. Šie modifikatoriai įtakoja kokios kitos klasės gali panaudoti klasės kintamuosius, kai kurias daugiagijiškumo operacijas. Kintamuosius galima paskelbti static arba final . Kiti kintamųjų modifikatoriai yra tokie: public , private , protected , static , final , transient ir volatile .
Kintamieji gali būti paskelbti public , protected , nutylimas "friendly" (kuris yra nerašomas) arba private .
public kintamasis gali būti panaudotas bet kurioje paketo kuriame jis buvo paskelbtas klasėje ir bet kurioje kitoje klasėje. Tai mažiausiai apribojantis (visai neribojantis) modifikatorius.
protected tarkime klasės C kintamasis yra prieinamas paketo klasėms, kuriame yra C klasė, ir klasės C poklasėms. Šis modifikatorius apriboja kintamojo panaudojimą kitų paketų klasėms, išskyrus tą atvejį, kai jos praplečia klasę C.
Jeigu C klasės kintamojo modifikatorius nenurodytas, kartais jis vadinamas "friendly". Toks kintamasis yra prieinamas paketo (kuriame yra C klasė) klasėms.
private kintamasis pasiekiamas tik tos pačios klasės metodams. Tai labiausiai ribojantis kintamojo panaudojimą modifikatorius. Klasės poklasės taip pat negali panaudoti private kintamuosius.
Čia pateikiamas pavyzdys, kuriame panaudoti visi keturi modifikatoriai:
class circle { public String className; protected int x,y; float spindulys; private int graphicsID; }
Jeigu kintamasis paskelbtas static , tai kompiliatorius realizuoja tik vieną jo egzempliorių ir jis turi tą patį vardą, kuriuo jis bovo paskelbtas. static kintamajam vieta išskiriama kompiliavimo metu. Todėl su tokiu kintamuoju iš karto galima dirbti nenaudojant new operatoriaus. Static kintamųjų pavyzdžių rasite matematinių klasių pakete Math . Pavyzdžiui taip galime atspausdinti konstantos p reikšmę:
System.out.println("PI:" + Math.PI);
final modifikatorius nustato, kad kintamojo reikšmė negali būti pakeista. Šis kintamasis iš karto turi būti inicijuojamas ir bet kuris bandymas į keisti iššauks kompiliavimo klaidą. final modifikatorius paprastai naudojamas apibrėžti konstantas. Konstantos dažniausiai nurodomos tokiu modifikatorių rinkiniu: public static final . Mes galėtume paskelbti konstantą mūsų klasėje foo taip:
class foo { public static final int atsakymas = 42; }
transient ir volatile modifikatoriai yra naudojami gijų programavime. Jie naudingi optimizuojant kodą. Raktažodis transient kol kas rezervuotas vėlesnėm Java kalbos versijoms.
volatile kintamieji yra keičiami gijose asinchroniškai. volatile kintamasis yra iškviečiamas naujai iš atminties ir išsaugojamas naujai atmintyje po kiekvieno jo panaudojimo. Šie du modifikatoriai yra rezervuoti ateičiai, juos galima naudoti ir Java 2 kalboje.
Metodų galimi modifikatoriai išvardinti 4-13 lentelėje. public , nutylimasis, protected ir private yra modifikatoriai analogiški klasių kintamųjų atitinkamiems modifikatoriams. Jie nurodo kokios klasės gali naudoti metodą.
public | protected | private | static |
abstract | final | native | synchronized |
static modifikatorius padaro metodą pasiekiamą net tuo atveju, kai klasė nėra inicijuota. static metodas netiesiogiai paskelbtas final ; todėl metodų negalima perkrauti kitais metodais. Viduje static metodo galima panaudoti tik tuos klasės narius, kurie taip pat yra static .
abstract metodo modifikatorius paskelbia, kad šis metodas bus realizuotas vėliau poklasėje. Jeigu jūs paskelbėte kokį nors klasės metodą abstrakčiu (abstract ), toks metodas negali būti toje klasėje aprašytas. Jeigu visi klasės metodai yra abstract , jums verta pamąstyti ar nebūtų geriau šią klasę apiforminti interfeisu.
final metodo modifikatorius paskelbia, kad šis metodas negali būti perrašytas klasės poklasėse. Optimizuojantys kodą kompiliatoriai final metodų kodą gali tiesiogiai įterpti į kompiliuojamąjį kodą ir taip sąskaita ilgesnio kompiliuoto kodo pagreitinti programos vykdymą. Tokia praktika dažnai taikoma C++ kalboje.
synchronized raktažodis naudojamas pažymėti metodus, kurie reikalauja gijų sustabdymo prieš vykdant metodą. Apie tai plačiau kalbėsime skyriuje "Gijų programavimas".
Jeigu jūs norite parašyti kodą, kuris naudojant to paties pavadinimo metodą apdorotų parametrus skirtingai, jums reikia perkrauti metodą. Gana dažnai tokia praktika taikoma klasių konstruktoriams. Lygiai tą patį galite atlikti ir su metodais, tik negalite perkrauti destruktoriaus. Reikalas tas, kad destruktorius turi fiksuotą vardą ir neturi parametrų.
Metodas perkraunamas panaudojant tą patį vardas ir tą patį grįžties tipą su skirtingomis parametrų tipų sekomis. Kiekvienas perkrautas metodas turi būti unikalus; unikalumas apibrėžiamas parametrų skaičiumi ir jų tipais. Parametrų vardai neturi įtakos vienačiai. Pavyzdžiui, pateiktas kodas nebus sukompiliuotas:
class foo { foo(int i) {...} // nebus sukompiliuota, foo(int j) {...} // nes metodų parametrų tipų sekos nesiskiria }
Pateiktas kodas turi du metodus, kurie turi tą patį parametrų sąrašą - vieną int tipo kintamąjį. Tokia metodo perkrova yra klaidinga.
Pakeitus parametrų sąrašo tipus, metodo perkrova bus galima:
class foo { foo(int i) {} foo(byte j) {} }
Šitas kodas bus sukompiliuotas ir bus pasiruošęs atlikti foo metodą, jei bus perduotas vienas int arba byte parametras. Tačiau gausite kompiliavimo klaidą, jei bandysite tam pačiam metodui perduoti short arba long tipo kintamąjį. Taigi Java neatlieka parametrų tipų konvertavimo ir šia savybe skiriasi nuo C/C++ kalbų.
Nuorodos tipo kintamųjų konvertavimas
Visos nuorodos į objektus ir interfeisus padaromos panaudojant nuorodų kintamuosius ( reference variables ), kurie kartais vadinami rodyklėmis ( pointers ). Jūs galėjote anksčiau kur nors perskaityti, kad Java nenaudoja rodyklių, tačiau tai ginčytinas teiginys. Java neturi rodyklių aritmetikos, bet savo esme nuorodų kintamieji yra rodyklės. Kad Java būtų saugesnė ir labiau nepriklausoma nuo platformų, jos kūrėjai nutarė palikti tik vieną būdą keisti nuorodos reikšmę; tas būdas yra paprastas priskyrimo operatorius.
Nuorodų kintamuosius apibrėžti lengva. Paskelbkite klasės arba interfeiso tipo kintamąjį, bet nepriskirkite jam reikšmės su new operatoriumi. Tuomet šiam kintamajam galėsite priskirti to paties tipo anksčiau sukurtus kintamuosius. Paskelbkime porą nuorodų kintamųjų; vieną tipo myClass klasės, kitą - shapes tipo interfeisą.
myClass myRef; shapes myShapes;
Priskiriant nuorodų kintamiesiems reikšmes reikia laikytis tam tikrų taisyklių. Visuomet leidžiama nuorodos kintamajam priskirti to paties tipo kintamąjį. Priskiriant vieno tipo nuorodai kito tipo nuorodą, interfeisą ar masyvą kyla klausimas ar toks priskyrimas yra leidžiamas. Vienais atvejais toks priskyrimas leidžiamas, kitais leidžiamas, jei naudojamas tipo apribojimo (cast) operatorius, o dar kitais atvejais priskyrimas neleidžiamas niekuomet. Automatinio tipo konvertavimo taisyklės yra gana sudėtingos. Kai kurias taisykles mes paaiškinsime, bet bendru atveju geriau studijuoti Java kalbos specifikaciją, kurioje rasite atsakymą visais atvejais.
Jeigu sukuriate S klasės tipo nuorodos kintamąjį, šiai nuorodai galite priskirti tokius tipus:
Jeigu sukuriate nuorodos kintamąjį interfeisui S, kiekvienas jo priskyrimas turi realizuoti S. Tipų suderinamumas turi būti apibrėžtas praginos metu, nes S poklasė gali turėti realizuotą interfeisą.
Kitais priskyrimo atvejais galima naudoti tipo apribojimo ( cast ) operatorių. Jeigu naudojate cast operatorių, galite gauti praginos klaidą. Jūs turite būti garantuotas, kad praginos metu objektas bus apibrėžtas arba turite būti pasiruošęs apdoroti castClassException praginos klaidą.
Interfeisas yra ekvivalentus klasei, kurios visi metodai yra paskelbti abstrakčiais (abstract ) ir kurių visi kintamieji paskelbti static ir final . Kiekvienas metodas yra nerealizuojamas ir visi kintamieji yra konstantos. Kiekvienas interfeiso kintamasis turi būti inicijuotas (priskirta pradinė reikšmė) ir kintamieji negali būti paskelbti transient arba volatile . Interfeiso metodai negali turėti modifikatorius final , native , static ir synchronized .
Kiekviena klasė kurios antraštėje paskelbta, kad ji implements (realizuoja ) interfeisą privalo realizuoti visus tame interfeise paskelbtus metodus. Interfeisas yra būdas kurti konceptualiai programas. Jis naudingas konstruojant objektų hierarchijas. Kai kurie programuotojai laikosi metodologijos pirma aprašyti visus interfeisus ir klases, nes tai palengvina kodų apjungimo problemos sprendimą. Vėliau, interfeisai yra realizuojami. Tokia maniera leidžia rašyti labiau abstraktų kodą, kuris vėliau yra lengvai praplečiamas.
Interfeisų apibrėžimas labai panašus į klasių apibrėžimą. Pagrindinis skirtumas yra tas, kad čia vietoje class naudojamas raktažodis interface . Apibrėšime shapeInterface interfeisą, kuris turi du metodus: draw ir erase:
public interface shapeInterface { public void draw(); public void erase(); }
Dabar galime realizuoti keletą skirtingų formų naudojančių šį interfeisą. Vėliau galėsime sukurti duomenų struktūras kuriose yra shapeInterface tipo kintamieji. Nepaisant konkrečios realizacijos bus galima naudotis interfeise paskelbtais metodai. Interfeisas yra galinga programavimo priemonė ir ypač naudinga gerinant kodo panaudojamumą ir suprantamumą.
Masyvas Array yra hibridinis pirminio ir objekto tipas. Vizualiai jis primena objektą, bet turi specialią prasmę kompiliatoriui. Klasė Array yra paskelbta final , taigi jūs negalite jos praplėsti savo funkcionalumu.
Masyvas naudojamas saugoti grupėje panašią informaciją. Visi masyvo vienetai kompiliavimo metu turi būti to paties tipo. Jeigu masyvas sudarytas iš pirminio tipo elementų, visi elementai turi būti to paties pirminio tipo; jeigu jis sudarytas iš nuorodos tipo kintamųjų, visos jos turi būti vienodo tipo.
Masyvas panašus į objektą, nes prieš naudojant naują masyvą pirma jį reikia inicijuoti su new operatoriumi; dar daugiau - kiekvienas nuorodų tipo masyvo elementas taip pat turi būti inicijuojamas new operatoriumi. Šiuo atžvilgiu Java masyvai skiriasi nuo daugelio kitų kalbų masyvų, nes kitose kalbose masyvo elementų nutylimuoju inicijavimu pasirūpina kompiliatorius.
Java masyvai ženkliai skiriasi nuo daugumos kalbų masyvų.
Sutaupysite daug laiko ateityje, jei jau dabar įsigilinsite į Java masyvų
naudojimo subtilumus. Nemanykite, kad Java masyvai yra tie patys kaip
C arba Paskalio kalbose. Jeigu esate susipažinę su smallTalk ,
tuomet jums pasisekė - joje naudojami masyvai yra analogiški Java masyvams.
Masyvai yra inicijuojami naudojant new operatorių. Kiekvienas masyvo elementas yra atskiras objektas. Masyvas yra savotiškas konteineris, kuriame talpinami visi objektai, ir kuris suteikia patogų priėjimą prie konteineryje patalpintų elementų.
Paprasčiausias masyvas yra vienmatis masyvas, kuriame talpinami pirminio tipo kintamieji. Paskelbkime ir inicijuokime sveikųjų skaičių masyvą, kuris turėtų 5 elementus:
int nums[] = new int[5];
Iš pateikto pavyzdžio aiški dauguma masyvo paskelbimo ir inicijavimo sintaksės taisyklių. Laužtiniai skliausteliai po tipo identifikatoriaus nurodo kompiliatoriui, kad šis kintamasis skirtas masyvui, kurio elementai turės pradžioje nurodytą tipą (mūsų pavyzdyje int tipą). new operatorius iškviečia nurodytą skaičių konstruktorių (pavyzdyje - 5) inicijuoti kiekvienam masyvo elementui. Turėdami tai omenyje nesunkiai suprasite ir daugiamačių masyvų sintaksę (apibrėžimo taisykles) ir semantiką (prasmę).
Java masyvai turi turėti bent vieną apibrėžtą dimensiją. Likusias galima apibrėžti praginos metu. Kad paskelbti ir inicijuoti dvimatį masyvą, galime parašyti tokį kodą:
class tarray { public static void main(String args[]) { int numsList[][] = new int[2][]; // Kitą dimensiją apibrėžiame vėliau numsList = new int[2][10]; for(int i=0; i< 10 ;i++) { numsList[0][i] = i; numsList[1][i] = i; } for(int i=0; i< 10; i++) { System.out.print(numsList[0][i] + " "); System.out.println(numsList[1][i]); } } }
Šitas kodas sukuria numsList masyvą, kurio nurodytas tik vienas matavimas. Mes galime apibrėžti kitą matavimą vėliau. Yra svarbu atsiminti, kad konstruktorių galime kviesti dėl kiekveino masyvo elemento. Šią Java kalbos savybę galime panaudoti sukuriant nestačiakampius masyvus. Sukurkime trikampį masyvą:
int[][] createArray(int n) { int[][] numeriai = new int[n][]; for(i=0; i< n; i++) { nums[i] = new int[i+1]; } return numeriai; }
Šis kodas sukuria trikampį masyvą iš n elementų. Pirmas elementas turės vieną elementą, kitas du elementus ir paskutinis turės n elementų. Toks masyvo elementų inicijavimo būdas atveria daug papildomų galimybių. Taigi prireikus bet kokios susietų duomenų struktūros galime panaudoti tam reikalui masyvą.
Masyvai gali būti inicijuojami jų sukūrimo metu parašant tarp riestinių skliaustų {} norimas pradines reikšmes. Šiuo atveju jums nereikės nurodyti bendrą masyvo elementų skaičių, nes kompiliatorius sukurs lygiai tokio ilgio masyvą kiek reikia patalpinti visas skliausteliuose nurodytas pradines reikšmes. Kad inicijuoti daugiamačius masyvus, inicijavimo metu jūs galite panaudoti vidinį tiesioginį inicijavimą, .
Pateiksime paprastą tiesioginio masyvo inicijavimo pavyzdį.
int nums[] = {1,2,3,4,5};
Inicijuojant dvimatį masyvą reikės vidinių inicijavimo riestinių skliaustų. Pateiksime paprastą tokio inicijavimo pavyzdį:
int mums[][] = {{1,1},{2,2},{3,3},{4,4},{5,5}};
Kaip matote, inicijuoti vienmatį ar dvimatį masyvą yra lengva. Inicijuojant daugiamačius masyvus naudojama analogiška sintaksė, tik šiuo atveju sunkiau susikurti vizualią masyvo interpretaciją.
Masyvo elementų indeksavimui galima panaudoti byte , short , int arba char tipų kintamuosius. Jūs negalite masyvo indeksuoti su long , slankaus kablelio arba logine reikšme. Jeigu jums reikia panaudoti vieną šių tipų, jūs turite atlikti tipo apribojimą, t.y. panaudoti cast operatorių.
Masyvo indeksas gali kisti nuo nulio iki masyvo ilgio minus vienas. Jūs galite rasti kiekvienos masyvo dimensijos ilgį panaudojant length kintamąjį. Pateiksime masyvo length kintamojo panaudojimo pavyzdį.
long sum(int[] list) { long result=0; for(int i=0; i< list.length; i++) { result = rezultatas + list[i]; } return rezultatas; }
Šitas kodas sudės bet kokio ilgio sveikųjų skaičių masyvo elementus. Tai pasiekiama panaudojant length kintamąjį, kuris parodo masyvo elementų skaičių.
Java tikrina ar masyvo indeksas priklauso galimai jo kitimo sričiai. Todėl jei indeksas bus neigiamas ar didesnis arba lygus už masyvo ilgį bus gaunama arrayIndexOutOfBoundsException klaida.
Java masyvai yra galingas instrumentas, bet už tai tenka sumokėti tam tikrą kainą. Kai kurie kompiliatoriai optimizuoti stačiakampiams masyvams, kiti - ne. Reikia suprasti, kad nestačiakampiai masyvai kiek sulėtina programos darbą, bet tai yra pažįstama dilema - programuojant dažnai tenka rinktis tarp programavimo kodo paprastumo ir programos efektyvumo jos vykdymo greičio prasme.
Programos vykdymo eigos kontrolė
Dauguma kompiuterio programų turi galimybę keisti jos vykdymo eigą. Tokios kalbos priemonės vadinamos valdymo komandomis . Tarp jų yra mums pažįstama if-else komanda ir ciklo komanda for . Visos kompiuterių programavimo kalbos turi valdymo komandas ir daugelis jų jums turi būti pažįstamos. Mes pakalbėsime apie kiekvienos detales, nors jūs esate laisvi pasirinkti tik tų aprašymą, kurias jūs nepažįstate arba nepakankamai gerai žinote. Trumpai apie valdymo komandų struktūrą:
if (boolean) statement1; else statement2; for(išraiška; loginė išraika; išraiška) komanda; while(boolean) komanda; do komanda; while(boolean); break žymė; continue žymė; return išraiška; switch(expression) { case reikšmė : komanda; .... default : komanda; }
Daugiausiai žinoma valdymo komanda yra if - else konstrukcija. Po if einanti loginė išraiška yra apskaičiuojama ir gaunamas loginis rezultatas true arba false . Rezultatas true priverčia vykdyti komandą stovinčią po if , o false atveju bus vykdoma po else parašyta komanda. Jeigu jums nereikia false atveju atlikti jokių veiksmų, tiesiog nerašote else ir problema išspręsta. Pateiksime paprastą if - else panaudojimo pavyzdį:
if (done == true) System.out.println("atlikau"); else System.out.println("tęsiu");
Jūs galite if-else komandas parašyti pakartotinai. if loginės išraiškos bus apskaičiuojamo paeiliui pradedant nuo kairiosios if tol, kol nebus rasta pirmoji true reikšmė. Jeigu nei viena if loginių išraiškų nėra true , tuomet bus vykdoma else komanda. Remiantis tokia konstrukcija galima atspausdinti tinkamą duotai temperatūrai tekstą:
int temp; if (temp < 0) System.out.println("Jo, šiandien šaltoka."); else if (temp > 100) System.out.println("Vanduo jau verda?"); else System.out.println("Gera šiandien diena!");
Jūs galite pažymėti tik vieną vykdomą po sąlygos tikrinimo komandą. Ką daryti, jei jums reikia atlikti keletą komandų? Šiuo atveju galima pasinaudoti bloku. Bloku vadinama grupė komandų, kurios patalpintos tarp riestinių skliaustų poros {}. Programos eigos valdymo operatorių atveju vieno bloko komandos yra atliekamos visos, jei bloke nepanaudoti specialūs anksčiau užbaigiantys darbą bloke operatoriai. Pasižiūrėkime pavyzdį:
int itemCount; boolean checkout; if (itemCount <= 10) { System.out.println("Ačiū, kad pradėjote patikrinimą"); checkout = true; } else { System.out.println("Pateikti galima ne daugiau 10 vienetų!"); checkout = false; }
Paskalyje blokai yra apibrėžiami begin/end pora. Java naudoja C/C++
susitarimą panaudoti blokui žymėti riestinius skliaustus.
Atkreipkite į vieną if-else komandos naudojimo problemą. Sudėtingesniais atvejais iškyla neaiškumas kuri else šaka bus skaičiuojama. Pateiktas kodas iliustruoja šią problemą:
int prekėsKaina, turiuPinigų; boolean šaliaNėraŽmonos; if (prekėsKaina <= turiuPinigų) // neteisinga kodas if (šaliaNėraŽmonos == true) System.out.println("Pirksiu"); else System.out.println("Nepakanka pinigų");
Pateiktas pavyzdys veiks ne taip, kaip tikisi daugelis nepatyrusių programuotojų. Čia iškyla problema: neaišku kuriam if skirta else šaka. else šaka yra visuomet asocijuojama su paskutiniu if ir todėl čia spausdinamas tekstas yra nekorektiškas. Problema yra sprendžiama panaudojant riestinius skliaustus su kuriais tiesiogiai nurodote if-else galiojimo lygį. Pataisykime savo nekorektišką kodą:
int prekėsKaina, turiuPinigų; boolean šaliaNėraŽmonos; if (prekėsKaina <= turiuPinigų){ if (šaliaNėraŽmonos == true) System.out.println("Pirksiu"); } else System.out.println("Nepakanka pinigų");
Teisingai panaudoti blokai daro jūsų kodą lengviau skaitomu ir apsaugoja nuo subtilių loginių klaidų. If-else komanda naudinga programavimo priemonės, tik reikia atidžiai sekti visas if-else poras.
while ir do-while komandos naudojamas dviem specifiniais ciklų atvejais. while komanda naudojama, kai jums tinka ir toks atvejis, kai ciklo kamienas nebus įvykdytas nei karto. Palyginimo išraiška apskaičiuojama prieš ciklo operatoriaus įvykdymą. Kada ši išraiška yra false , ciklas užbaigiamas. Kad negauti be galo vykdomą ciklą, jūs turite pakeisti loginės išraiškos kintamųjų reikšmes ciklo kamieno viduje. Tarkime rezult() metodas grąžina loginę reikšmę. Tuomet galima tokia while konstrukcija:
while( result() ) { // Vykdomos ciklo kamieno komandos .... }
Šitas ciklas bus vykdomas tol, kol funkcija rezult() grąžins false reikšmę. Jeigu ji pačioje pradžioje grąžina false , ciklas nebus įvykdytas nei karto. Jeigu mes norime, kad ciklo kamienas būtų vykdomas mažiausiai kartą, galime naudoti do-while ciklą. Šio tipo ciklas bus vykdomas bent kartą, nepaisant jo palyginimo išraiškos. Naudojant tą pačią loginę funkciją galėsime parašyti naują kodą, kur būsime garantuoti, kad ciklo kamieno komandos bus vykdomos bent kartą:
do { // Vykdomos komandos .... } while ( result() );
while ir do-while komandos naudojamos pakartotiniems skaičiavimams atlikti. Yra dar viena ciklo konstrukcija naudojanti raktinį žodį for . Ši konstrukcija savo funkcionalumu nesiskiria nuo pirmų dviejų, tačiau for panaudojimas daro jūsų kodą lengviau skaitomu.
for komanda yra galingas ciklinių skaičiavimų organizavimo instrumentas. Po for operatoriaus ciklo išraiškos pradžioje yra inicijuojamas ciklo kintamasis (skaitliukas), toliau eina palyginimo išraiška ir tuomet ciklo kintamojo keitimo išraiška. Tipiniu atveju ciklo kintamasis (skaitliukas) yra padidinamas arba sumažinamas vienetu. Pateiktas pavyzdys paeiliui atspausdins skaitliuko reikšmes nuo 0 iki 4:
for(int i=0; i< 5; i++) { System.out.println(i); }
Trys ciklo išraiškos apskaičiuojamos skirtingais būdais. Pirma išraiška (inicijavimo segmentas) įvykdomas vieną kartą pačioje ciklo vykdymo pradžioje. Antroji išraiškos tikrinimo dalis atliekama cikliškai kiekvienos ciklo iteracijos pradžioje įskaitant ir patį pirmąjį kartą. Paskutinė trečioji dalis įvykdoma po ciklo kamieno užbaigimo; šioje dalyje standartiniu atveju ciklo išraiškos kintamasis padidinamas arba sumažinamas vienetu.
Iš pateikto pavyzdžio matyti, kad ciklo skaitliuko kintamasis i buvo paskelbtas ciklo išraiškos viduje, t.y. buvo panaudotas operatorius int i; . Tai yra leidžiama, nes ciklo išraiška laikoma nauju vidiniu programos bloku ir nepriklausomai nuo to ar ciklo kintamasis buvo paskelbtas ar ne jūs turite teisę jį paskelbti ciklo išraiškos viduje. Ciklo skaitliuko paskelbimas išraiškos viduje yra rekomenduotinas, nes tai apsaugoja nuo sunkiai aptinkamų anksčiau paskelbtų tuo pačiu vardu kintamųjų reikšmių neprognozuoto pakeitimo. Taip pat toks kodas yra lengviau skaitomas.
Toliau ciklo išraiškos antroje dalyje yra palyginimo išraiška. Ji grąžina loginę reikšmę. Skirtingai nuo C/C++ kalbų išraiška negali grąžinti sveikojo skaičiaus. Reikalas tas, kad C/C++ kalbose laikomasi susitarimo, kad bet kokio tipo sveikojo skaičiaus reikšmė 0 gali būti naudojama logine false reikšme, o visi kiti sveikieji skaičiai atitinka true . Java atveju toks dvilypis sveikųjų skaičių panaudojimas draudžiamas. Taip yra pasiekiamas didesnis Java kodo skaitomumas.
Visos ciklo antrosios dalies išraiškos turi grąžinti loginę reikšmę.
Čia neleidžiama panaudoti sveikosios išraiškos, nes Java sveikojo
skaičiaus niekuomet neinterpretuoja logine reikšme.
Paskutinė for komandos išraiškos dalis apskaičiuojama cikliškai kiekvieną kartą pabaigus vykdyti ciklo kamieno komandas. Ciklo išraiškos skaitliukas nebūtinai turi būti keičiamas vienetu; su for komanda galima imituoti kitas ciklo konstrukcijas. Pateiksime tokio for panaudojimo pavyzdį:
boolean cont = true; .... for(; cont == true;) { // Komandos kurios atlieka kokius nors veiksmus ... // Naujos cont reikšmės apskaičiavimo komandos ... }
while komanda turi palyginimo komandą, kurios patikrinimu prasideda ciklas. Jeigu palyginimo reikšmė false , ciklas nebus vykdomas nei karto. Naudojant for ciklo išraišką, kurioje praleista inicijavimo dalis imituojamas while ciklas. Pastebėkime kad kabliataškis nėra praleidžiamas, nors ciklo skaitliuko inicijavimo operatorius šiuo atveju yra praleistas.
Java turi galimybę lanksčiai reguliuoti ciklo kamieno vykdymą. Tarkime jūs turite ciklą kuris paprastai vykdomas 10 kartų, bet ketvirtadieniais jį reikia atlikti tik keturis kartus. Panašaus tipo atvejais naudojami programos vykdymo eigą keičiantys Java operatoriai break ir continue.
break komanda naudojama perkelti programos vykdymą už ciklo konstrukcijos( for, do, while, switch ) pabaigos. Ciklas bus užbaigiamas nepaisant jo palyginimo reikšmės ir bus vykdoma einanti po ciklo pabaigos komanda. Užbaigiant while ciklą galime panaudoti break komandą, be kurios ciklas gali ir niekada nesibaigti:
int i=0; while(true) { System.out.println(i); i++; if (i > 10) break; }
Šiuo atveju bus paeiliui atspausdinti sveikieji skaičiai nuo 0 ir iki 10.
continue komanda panaši į break komandą. continue komanda priverčia programos vykdymą tęsti praleidžiant po sutikto continue ciklo kamieno komandas. Pavyzdžiui pateiktame kode paprastai išvengiama dalyba iš nulio:
for(int i = -10; i< 10; i++) if (i == 0) continue; System.out.println(1/i); }
Šis ciklas neatliks dalybos, kai i == 0. Atkreipkime dėmesį, kad i++ bus apskaičiuojamas ir tuo atveju, kai kamieno vykdymą nutrauks continue operatorius. Jei taip nebūtų, tai parašytas kodas būtų vykdomas be galo, nes nepakistų i reikšmė 0.
Ir break ir continue komandos gali naudoti valdymo perdavimą žyme ( label ) pažymėtai programos daliai. Žymės sintaksė yra tokia: pirma rašomas žymės vardas, po to dvitaškis ir toliau einantis programos kodas. Praktiškai tai atrodo taip:
loop: for(int i=0; i< 10; i++) { }
Žymių ir valdymo operatorių panaudojimas imituoja daugeliui pažįstamą kitų kalbų goto operatorių, tačiau Java atveju šis operatorius tiesiogiai nenaudojamas. Tarkime susidūrėte su situacija, kai jums reikia nutraukti daugelio įdėtų ciklų vykdymą, kai tik bus rastas ciklo elementas su reikšme 5. Todėl mes pažymėsime išorinį ciklo operatorių žyme ir perduosime jos pabaigai valdymą, kai bus rasta masyvo reikšmė 5:
int i=-1,j=-1; int nums[][] = new int[5][5]; boolean found = false; loop: for(i=0; i<5; i++) { for(j=0; j< 5; j++) { if (nums[i][j] == 5) { found = true; break loop; } } } if (!found) System.out.println("Reikšmė nerasta"); else System.out.println("Rasta taške " + i + "," + j);
Šitas kodo fragmentas programavimo kalbų pradinukams gali atrodyti nesuprantamas, nes jame integruotai panaudoti ciklų, masyvų ir vykdymo eigos valdymo programavimo elementai.
return komandos esmė panaši į break , tik ja yra užbaigiamas ne ciklo bet metodo vykdymas. Papildomai po return gali būti nurodyta išraiška, kuri bus apskaičiuota ir grąžinta iškvietusiajam metodui. Užprogramuosime kėlimą n-uoju laipsniu:
class power { public int toN(int base, int n) { int result=base; for(int i=0; i< N - 1; i++) result = rezult * base; } return rezult; } }
Šitas kodas apskaičiuoja pagrindo base n-ąjį laipsnį. Čia panaudota return komanda, kad grąžinti apskaičiuotą rezultatą. Kitas kodas po return komandos nebus vykdomas. return komanda grąžinamos reikšmės tipas turi būti tas pats kaip ir metodo tipas. Jeigu metodas turi void grįžties (return ) tipą, tai po raktažodžio return rašomas iš karto kabliataškis. Taigi return atlieka dvigubą paskirtį: ji kontroliuoja metodo užbaigimą ir grąžina metodo skaičiavimų eigoje gaunamą reikšmę.
Senesnėse programavimo kalbose dažnai tekdavo rašyti ilgas if-else grandines. Toks pakartotinų if-else operatorių panaudojimo poreikis kaip taisyklė atsiranda formuojant meniu punktus. switch komanda iš esmės palengvina ir praskaidrina programas pakeisdama daugelį if-else komandų vienu switch operatoriumi.
switch komandoje galimos char , byte , short ir int tikrinimo išraiškos. Gauta reikšmė ieškoma tarp case šakų, kurios eina po switch komandos ir tos šakos, kuriose reikšmė randama yra vykdomos. Panaudokime switch komandą:
int cmd; // tarkime vartotojas įveda komandą switch(cmd) i { case 1 : System.out.println("Menu Item 1"); break; case 2 : System.out.println("Menu Item 2"); break; default : System.out.println("Invalid Command"); }
Po case stovinčios reikšmės turi būti to paties tipo kaip ir switch išraiškos rezultatas. Galima viena speciali žymė default , kurios šaka bus vykdoma, jeigu switch išraiškos reikšmė nebus rasta tarp likusių šakų.
Atkreipiame dėmesį į break komandos panaudojimą. Jei break šakoje nenaudojama, tai papuolus į tą šaką ji bus vykdoma ir toliau pereinama prie eilinės šakos tikrinimo. Kartais tokia vykdymo eiga pageidautina, kartais ne. break panaudojimas nutraukia kitų šakų tikrinimą. break galite naudoti arba nenaudoti kiekvienai šakai individualiai ir tokiu būdu grupuoti vykdomas šakas.
Java kalba buvo padaryta remiantis C/C++ kalbomis, nes jos turėjo Java atsiradimo metu plačiausią vartotojų ratą. Tačiau Java toli gražu nėra šių kalbų mišinys. Kalbos saugumas yra viena išskirtinių Java savybių. Java autoriai skelbė, kad tai yra C++ su išspręstomis saugumo problemomis ir daugiagijo programavimo galimybėmis.
Išimčių (exceptions ) apdorojimas yra tipinė programų dirbančių tinklo aplinkoje dalia. Tinklo vartotojai iš savo patirtie žino kaip dažnai ir neprognozuotai gali nutrūkti ryšys. Jūsų programa turi būti pasiruošusi išlikti gyvybinga ir tokiomis aplinkybėmis. Galime įsivaizduoti groteskinę programą, kuri po kiekvieno operatoriaus rašo tas pačias tinklo ryšio tikrinimo komandas. Tinklų programavimo pradžioje kažkas panašaus ir buvo daroma. Geras išimčių programavimas neįmanomas, jei kalboje nėra numatyta adekvačių priemonių. Java kalboje tokios programavimo priemonės yra.
Išimtims perduodamas valdymas, kai praginos metu sistema susiduria su kritine situaciją, kuri neleidžia toliau tęsti normalią programos eigą. Tipiniai pavyzdžiai yra dalyba iš nulio arba panaudojimas tuščios (null) nuorodos. Jei jūs savo programoje nenumatėte tokios situacijos apdorojimo, tai programos vykdymas bus sustabdytas. Priešingu atveju, kai parašėte specialų išimties atvejui kodą, kuris leidžia toliau tęsti programos vykdymą, programa tuo atveju išliks gyvybinga ir pratęs savo darbą. Net jei problema neturi sprendimo, galite parašyti išimties apdorojimo kodą skirtą išsaugoti tuo momentu sukauptą naudingą informaciją ir atlaisvinti užsakytus kompiuterio resursus.
Techniškai išimčių (exceptions ) apdorojimo mechanizmas realizuojamas panaudojant try ir catch komandas. Šios komandos nustato kodo bloką kuriam numatytas apdorojimas išimties atveju. Kodo bloką nurodote po try pažymėdami jį kaip įprasta tarp riestinių skliaustų, o catch nurodo kiekvienai generuotai išimčiai savą apdorojimo būdą. Ištirkime paprastą dalybos iš nulio problemą:
int i = 0; i = i / i;
Vykdydama šį kodą, Java pragina generuos išimtį (exception ). Programa bus pabaigta ir bus atspausdintas klaidos pranešimas ekrane. Už programą užmokėjęs jūsų klientas paskambins jums kaip tik tuo metu, kai sėdate už šventinių pietų stalo. Ar nebūtų geriau pasirūpinti, kad klientams būtų mažiau suteikiama pretekstų gadinti jums gyvenimą? try / catch mechanizmas ateina į pagalbą sprendžia tokio tipo problemas:
int i = 0; try { i = i / i; } catch (ArithmeticException e) { System.out.println("Dalyba iš nulio, toliau tęsiu darbą"); }
Po try bloko galite nurodyti bet kokį catch blokų skaičių. Po kiekvienos išimties praginos sistema sukuria klaidą aprašantį objektą. Šis klaidos aprašymo objektas praplečia Exception klasę. Toliau yra perduodama programos vykdymo eiga išimčių apdorojimui. Jei nėra nei vieno išimties apdorotojo, programa sustabdoma. Savo programoje mes numatėme ArithmeticException išimties apdorojimą. Tačiau kitų išimčių atveju mūsų programos vykdymas sustotų.
Gavęs išimties generavimą, kompiuteris ieško tarp visų catch blokų kurie galėtų ją apdoroti. Pirmiausiai ieškomas geriausiai sutampantis. Jeigu nerasta tiksliai sutampančio, tuomet keliaujama paveldėjimo medžiu, kad rasti artimiausią tinkamą. Kadangi aritmetinė išimtis (ArithmeticException ) yra Exception poklasė, mūsų atveju ji ir bus pasirinkta. Šią koncepciją lengviau suprasti analizuojant pavyzdžius.
int i = 0; try { i = i / i; } catch (ArithmeticException e) { System.out.println("Dalyba iš nulio, toliau tęsiu darbą"); } catch (Exception e) { System.out.println("Turime tam tikrų problemų"); // Vykdome resursų atlaisvinimo operacijas ... // Atkuriame išimtis throw(e); }
Pateiktame kode galite pastebėti problemą. Mes galime gauti išimtį, bet nežinosime su kokia išimtimi turime reikalą. Jeigu nežinote kaip ją apdoroti, tai geriausia duoti tai padaryti praginos sistemai. Čia mes taip ir darome - pirma atlaisviname resursus, o toliau išimties apdorojimo darbą perduodame praginos sistemai.
throw komanda perduoda objektą išimties apdorojimo grandinei. Galite turėti daugelio lygių try ir catch sistemą. throw komanda ignoruoja einamąjį lygį ir ieško naujo tinkamo išimties apdorojimo. Jei tokio neatsiras, programa bus sustabdyta.
Kartais jums reikia įvykdyti kodo dalį net tuo atveju, kai buvo generuota išimtis. Tokiu atveju reikiamas vykdyto blokas patalpinamas po finally komandos. Nepriklausomai dėl ko try bloko vykdymas buvo baigtas (ar sėkmingai iki bloko galo, ar anksčiau pabaigtas dėl išimties, dėl valdymo su break ar continue), finally blokas visuomet bus vykdomas. try , catch ir finally skeletonas atrodo taip:
try { // bandyk atlikti kodą, kuriame gali pasitaikyti išimčių } finally { // atliekame bet kuriuo atveju reikalingas komandas } catch (ArithmeticException e) { // adorojame dalybos iš nulio išimtį }
Pateiktas programos skeletonas yra geras karkasas dirbant su kodo dalimi, kurioje gali būti generuotos išimtys (exceptions ). Toks kodo blokas apjungiamas try komanda. Išimčių apdorojimas padaro jūsų programą žymiai gyvybingesne.
4-14 lentelėje bendras generuojamų praginos sistema išimčių sąrašas. Dauguma API klasių turi savas išimtis. Kai naudojate naują klasę, susipažinkite su išimtimis, kurias ji gali generuoti.
Išimtis (exception ) | Aprašymas |
---|---|
ArithmeticException | Išimtys atsirandančios atliekant aritmetinius veiksmus. Pavyzdžiui, dalyba iš nulio. |
ArrayIndexOutOfBoundsException | Jūs panaudojote indeksą, kurio reikšmė nepatenka į masyvo rėžius. Prisiminkite, kad masyvo elementai indeksuojami pradedant nuo 0 ir baigiant N-1, kur N yra masyvo ilgis. |
ArrayStoreException | Jūs bandote saugoti blogo tipo objektą masyve. Objektas turi būti arba to paties tipo, arba poklasė, arba objektas kuriame realizuojamas nurodytas interfeisas. |
CastClassException | Blogai panaudotas tipo apribojimo operatorius cast. |
InstantiationException | Jūs bandote inicijuoti interfeisą arba abstrakčią klasę. |
NegativeArraySizeException | Bandote sukurti neigiamo ilgio masyvą. |
nullPointerException | Bandote panaudoti nuorodos kintamąjį, kuris nėra inicijuotas arba yra tuščias ( null ). |
NumberFormatException | Eilutės reikšmė negali būti konvertuota į skaičių. |
OutOfMemoryError | Netgi surinkus šiukšles, nepakanka atminties tolimesniam programos vykdymui. Naujiems kompiuteriams su dideliais resursais tai atsitinka retai, bet teoriškai taip gali būti. |
SecurityException | Bandote atlikti operacijas, kurios dėl saugumo apribojimų neleidžiamos atlikti. |
StringIndexOutOfBoundsException | Mėginant panaudoti eilutę kaip masyvą, jūs nurodėte indekso reikšmę, kuri nepatenka į eilutės masyvo rėžius. |
Į šį skyrių galėsite visuomet atsigręžti, kai iškils sintaksės klausimai. Dabar subrendome linksmesniems dalykams - pasiaiškinti kaip veikia įskiepiai. Kitame skyriuje išmoksime kurti interaktyvius įskiepius, kurie galės papuošti jūsų Interneto puslapius.