Primitiv Məlumat Tipləri (Java-da)
Bəşər övladı 9.1 * 10^-28 q-lıq kiçicik bir zərrəcikdən(elektron-dan), ucsuz-bucaqsız kainata qədər mövcud olan hər şeyi və onların xüsusiyyətlərini daima öyrənməkdədir. Bu məqsədlərə çatmağın yolu mütaliə, müşahidə və təhlili özündə cəmləyən bir məfhumdan-araşdırmadan keçir. Bütün araşdırmalardakı ən fundamental sual isə “bu (və ya o) nədir?”-dən başqa bir şey deyil.
İndi təsəvvür edin ki, bir siz varsınız, bir dostunuz, bir də sizdən 2m(məs.), dostunuzdan 5m(məs.) məsafədə olan bir stol və həmin stolun üstündə bir şəkil. Ona uzaq olduğu üçün stolun üstündəkinin nə olduğunu görməyən dostunuz sizdən soruşur : O nədir? Siz cavab verirsiniz ki, “bu şəkildir”. Amma şəkildən çox şəkil var axı, bəs niyə belə cavab verdiniz? Çünki dostunuz əslində sizdən stolun üstündəkinin tam olaraq nə olduğunu yox, nəyə bənzədiyini, hansı növə-hansı tipə aid edilə biləcəyini soruşurdu. O qədər çox məlumatla əhatə olunmuşuq ki, oxşar xüsusiyyətliləri, ortaq xassələrinə görə sinifləndirməsəydik bu qədər sağlam təhlillər həyata keçirərək əşyaları, eləcə də digər, gözəgörünməz canlı-cansız varlıqları və hadisələri indiki kimi tez anlaya bilməzdik. Yaxşı bəs şəkil nədir? Deyəcəksiniz ki, müxtəlif və ya eyni rənglərdə və ölçülərdəki cisim(lər)in 2d-lik kağız üzərində mücəssəməsi. Və rədd oluna bilməz bir həqiqətdir ki, başqa cismlərin də rəngləri, ölçüləri və s. xüsusiyyətləri olur. Yəni, ağappaq bir vərəqin də, qara bir lövnənin də rəngi var(amma fərqlidirlər). Eyni tip, fərqli seçim. Bütün cisimləri xüsusiyyətləndirmək üçün istifadə etdiyimiz, öz daxilində özündən başqa heç bir xüsusiyyəti olmayan rəng, həcm, və s. kimi bəsit xüsusiyyətlər-tiplər proqramlaşdırmada ingilis dillilərin təbiriylə desək “primitive data types” yəni, primitiv məlumat tipləridir. Şəkil kimi bəsit xüsusiyyətləri-primitiv tipləri özündə cəmləyən tiplərin programlaşdırmadakı analoqu isə istinad tipləri(reference types) adlanır. Yəni, məlumat tipləri(data types) 2 yerə bölünür: primitiv tiplər(primitive types) və istinad tipləri(reference types). To refer sözü ingiliscədən müraciət etmək kimi tərcümə olunur və bu, obyektər yaratmaq üçün istifadə olunan istinad tiplərinin hər bir obyekti özündə fərqli istinad tip(lər)in və ya öz tipinin başqa bir obyektinə müraciət edə bilir. Qeyd edim ki, bir istinad tipinin obyekti başqa bir obyekti yəni hansısa bir istinad tipinin(refernce type-ın) modelində yaradılmış nümunəni(instance-ı) tam olaraq primitiv tiplərlə etdiyi kimi öz içində saxlaya bilmir. Yalnızca müraciət edir(“refer eləyir”). Istinad tiplərin izahatında primitiv tiplər həyati əhəmiyyət daşıdığı halda, primitiv tipləri anlamaqda istinad tiplər(reference types) haqqında yuxarıda dediklərimdən savayı heç nəyə ehtiyac duyulmadığından, proqramlaşdırma dilləri barəsində kiçik bir məqama daha toxunub keçirik məqaləmizin o biri hissəsinə, primitiv tiplərin spesifikasiyaları-xüsusiyyətləri və istifadə qaydalarına.
Azərbaycan, türk, ingilis dili kimi dillər insanla insan, proqramlaşdırma dilləri isə proqramçı ilə komputer arasında ünsiyyət vasitəsidir. Azərbaycan dilindəki “o”(şəxs əvəzliyi, 3-cü şəxsin təki) ingilis dilində “he”(kişi), “she”(qadın), “it”(cansız) kimi 3 tipdə səslənir. İngilis dili kimi dillər bununla həm qarışıqlıqların önünü kəsir, həm də fikrin daha tez anlaşılmasını təmin edir. Bu təhlükəsizliyin proqramlaşdırmadakı analoqu “type safety” yəni tip təhlükəsizliyidir. Proqramçı komputerə məlumatları konkret tiplərini tanıdaraq daxil edirsə, istifadə olunan proqramlaşdırma dili statik olaraq tiplərə ayrılmış və ya statically typed(məs. c, c++, c#, java, kotlin, swift) yox əgər, yalnız bir tipdə daxil edir və komputer özü onları tiplərə ayırırsa, istifadə olunan proqramlaşdırma dili dinamik olaraq tiplərə ayrılmış və ya dynamically typed dillərə aid edilir.(məs. javascript, python, php, objectibe-c, ruby, R, matlab kimi)
byte – 8-bit, signed 2’s complement tam ədəddir. Burdakı 8-bit byte tipinin ölçüsü, yəni byte tipindəki bir dəyişənin əməli yaddaşda(RAM-də) tutduğu yerdir. byte tipindəki bir dəyişən 8 xanada hərəsində 2 mümkün hal(0 və ya 1) olmaqla 2^8 = 256 ədəddən birini yadda saxlaya bilir. Bəs bu 256 ədəd hansılardır? Və ya belə deyək, bu ədədlər hansı aralıqdadırlar? Signed 2’s complementin nə demək olduğunu anlayanda bu sualın cavabı sizə aydın olacaq. Verilmiş ölçülü tipdəki bir dəyişənin əhatə edə biləcəyi ədəd aralıqları iki fundamental prinsipə əsasən təyin olunur:
- İşarələnmiş(signed): mənfi ədədlər, 0 və müsbət ədədləri özündə ehtiva etdiyindən ədədin nə vaxt mənfi, nə vaxt müsbət olduğunu bilmək üçün işarələnməyə(ingiliscədə signed “to sign”-işarələmək sözündən götürülüb) ehtiyac duyulur. Ədədləri işarələnmiş(signed) olaraq yadda saxlamaq üçün 3 təqdimetmə texnologiyası(representation) var. (0(sıfır) bir texnologiyada müsbət, digər ikisində isə həm mənfi, həm də müsbətlərin tərəfində yerləşir(+0, -0))
3 texnologiyanın üçündə də ədədin ilk biti (soldan birinci) 0 olduqda müsbət, 1 olduqda mənfi olması müştərəkdir.
-
- İşarə-miqdar təqdimetmə texnologiyası (sign-magnitude representation):
Qalan (n-1) bitin dəyəri həmin ədədin miqdarını (modulunu) təşkil edir.
-
- 1-ci tərs təqdimetmə texnologiyas(1’s complement representation)ı:
Ədəd müsbət olduqda (n-1) bitin dəyəri, mənfi olduqda isə (-127 + (n-1) bitin dəyəri) həmin ədədin miqdarını (modulunu) təşkil edir.
-
- 2-ci tərs təqdimetmə texnologiyas(2’s complement representation)ı:
Ədəd müsbət olduqda (n-1) bitin dəyəri, mənfi olduqda isə (-127 + (n-1) bitin dəyəri) həmin ədədin miqdarını (modulunu) təşkil edir.
Aşağıdakı şəklin yuxarıda yazdıqlarımın daha yaxşı anlaşılmasına kömək edəcəyi inancındayam. Şəkil 1:
2. İşarələnməmiş(unsigned) yalnız 0 və müsbət ədədləri özündə cəmlədiyindən ədədin dəyəri işarələnmişdəki (signed-dakı) ən yüksək modul dəyərinin iki qatından bir əskikdir. (2n-1)
Dedik ki, byte işarələnmişdir(signed-dır). Beləliklə, 2^8-in yarısı – 2^7 (2^8 = 2 * 2^7) mənfi hissəyə, 0 və qalan 2^7-1 də müsbət hissəyə düşür ki, bu da [-128; 127] ([-2^7; 2^7 – 1]) aralığıdır. Amma əgər byte işarələnmiş(signed) yox, işarələnməmiş(unsigned) olsaydı [0; 255]( [0; 2^8-1]) aralığındakı ədədlərin istifadəsinə izin verərdi. Amma belə deyil!
Əgər aşağıdakı şəklə ad verə bilsəydim onu “byte – işarələnmiş 2-ci tərs tam ədəd(signed 2’s complement integer) kimi” adlandırardım. Şəkil 2:
short – ölçüsü: 16-bit, aralığı: [-32,768; 32,767]([-2^15; 2^15 – 1]), işarələnmiş 2-ci tərs tam ədəddir (signed 2’s complement integer).
int – ölçüsü: 32-bit, adi halda (default) aralığı: [-2,147,483,648; 2,147,483,647]([-2^31; 2^31 – 1]), işarələnmiş 2-ci tərs tam ədəddir (signed 2’s complement integer). Amma JavaSE8 və sonrakı versiyalarda int 32-bitlik işarələnməmiş tam ədəd (unsigned integer) kimi də istifadə oluna bilər. Yəni, [0; 4,294,967,296] ([0; 2^32 – 1]) aralığını reserv edə bilir. Ancaq işarələnməmiş int-in (unsigned int-in) istifadəsi ‘c’-də,’c++’-da olduğu kimi rahat və çoxşaxəli deyil, yalnız java.lang.Integer sinifindəki(class-ındakı) bəzi methodlarla üzərində azsaylı əməliyyatlar(operations) aparıla bilir. Şəkil 3:
Aşağıdakı nümunədə bu metodlardan bir neçəsinin tədbiqini görə bilərsiniz:
Nümunə(Şəkil 4):
Çıxış (Konsolda çap olunacaqlar)(Şəkil 5):
Diqqət yetirin, nümunədə x və y dəyişənlərinin əməliyyatdan(operation-dan) sonrakı dəyəri int-in adi haldakı(default) qiymət aralığını ([-2,147,483,648; 2,147,483,647]) aşır. Bu da int-in JavaSE8 və ondan sonrakı versiyalardakı işarələnməmiş(unsigned) ola bilmə funksionallığından irəli gəlir.
Əgər nümunədə
</p> <p class="MsoNormal" style="margin-left: .5in">long ux = İnteger.toUnsignedLong(x);</p> <p class="MsoNormal" style="margin-left: .5in">
əvəzinə
</p> <p class="MsoNormal" style="margin-left: .5in">long ux = x;</p> <p class="MsoNormal" style="margin-left: .5in">
olsaydı, long tipindəki ux dəyişəninin dəyəri -1 olardı. toUnignedLong(….) metodu isə x dəyişəninin -1 dəyərini yadda saxladığı 1111111111111111(int 32-bitdir, amma adi halda(default olaraq) işarələnmiş(signed) olduğundan həm mənfi, həm də müsbət ədələri özündə saxlamaq üçün sadəcə 16 bit-ə ehtiyac duyulur. Xatırla: ilk(soldan birinci)bit 0 olduqda ədəd müsbət, 1 olduqda mənfi) ikili ədədləriylə təqdimatını(binary representation-ınını) (birazdan haqqında daha ətraflı məlumat alacağınız)long-un 64-bitlik yaddaşının 32 “qrafa”-sının sağ yarısına köçürür. Nəticədə ux-in dəyərinin ikili təqdimatı(binary representation-ı) 00000000000000001111111111111111 olur ki, bu da biz insanların daha rahat başa düşdüyü 10-luq sistemdə 4,294,967,295-dan başqa bir şey deyil.
</p> <p class="MsoNormal" style="margin-left: .5in">int uQuotient = İnteger.divideUnsigned(x, y);</p> <p class="MsoNormal" style="margin-left: .5in">
əvəzinə
</p> <p class="MsoNormal" style="margin-left: .5in">long uQuotient = ux / uy; </p> <p class="MsoNormal" style="margin-left: .5in"> [java]</p> <p class="MsoNormal" style="margin-left: .5in"> yazsaydıq da nəticədə(konsola(console-a) çap olunan dəyərdə-çıxışda) fərq olmazdı. Fəqət nümunədəki divideUnsigned(....) metodu adi halda(default olaraq) işarələnmiş(signed) olan int tipindəki dəyişənlərin işarələnməmiş(unsigned) dəyərlərini long-lara çevirmədən işlədilir. Yəni, divideUnsigned(....) methodu adi halda(default olaraq) işarələnmiş(signed) olan int tipindəki x və y parametrlərinin(methodun çağırıldığı və həmin metodun içində işlədilə biləcək dəyişənlər) işarələnməmiş(unsigned) dəyərlərini öz daxilində long-lara “yükləyib” üzərində bölmə əməliyyatını(divide operation-ı) yerinə yetirir. Java-da iki tam ədədi bir-birinə böləndə qismətdə kəsr hissəsi atıldığından(Python-dakı // operatoru kimi) 4,294,967,295 / 4,294,967,294 1-ə bərabər olur.</p> <p class="MsoNormal" style="margin-left: .5in"> </p> <p class="MsoNormal" style="margin-left: .5in">long - 64-bit ölçülü, adi halda (default olaraq)[-9,223,372,036,854,775; 9,223,372,036,854,774] ([-2^63; 2^63 - 1])işarələnmiş 2-ci tərs tam ədəddir (signed 2’s complement integer-dir). long da JavaSE8 və sonrakı versiyalarda işarələnməmiş(unsigned) ədəd kimi istifadə oluna bilir amma işarələnməmişə(unsigned-a) çevrilə biləcək, int-dəki toUnsignedLong(....) kimi method yoxdur (əslində, java dili compiler səviyyəsində işarələnməmişliyi(unsigned olma xüsusiyyətini dəstəkləmir), işarələnməmiş olma xüsusiyyətini bu dilə “bəxş edən” dil dəstəkçilərinin yazdıqları API-lardır(metodlardır), ona görə də bizim haqqında danışdığımız tiplər arasında get-gəl və bitlər səviyyəsindəki əməliyyatlardan (bitwise operation-lardan) başqa bir şey deyil), fəqət yenə də compareUnsigned(....), divideUnsigned(....) metodları bu tip üçün də mövcuddur və bu halda long [0; 18446744073709551615] ([0; 2^64 - 1]) qədər böyük bir aralığa sahib olur.</p> <p class="MsoNormal" style="margin-left: .5in">Float: Bura qədər haqqında danışdığımız primitiv tiplər(primitive types) tam ədədlər idi. float isə kəsr ədədir, 32-bit ölçülü, IEEE 754 standartlarına uyğun birqat dəqiqlikli(single precision-dakı) kəsr ədəd. IEEE 754, birqat dəqiqlik(single precision)... Bu terminləri araşdırarkən kəsr ədədlər üzərində əməliyyatların(operation-ların) bəzən çox uzun olduğunu və hətta cavabın kəsr nöqtəsindən sonra sonsuz ədəd daşıya biləcəyini bilirdim amma komputerin ədədin tam, kəsr və “10 üstülərinin”(məs. 1.4 * 10^5 ədədində, 5) hər biri üçün sabit sayda, məhdud ölçüdə yer ayırdığını düşünməmişdim. Yəni, float-dan(və eləcə də birazdan haqqında oxuyacağınız double-dan) istifadə edərək riyazi hesablamalar apardıqda (xüsusən, bir neçə dəfə təkrarən) gözlə görünür səhvlər ortaya çıxa bilər. Əgər dəqiq nəticələr əldə etmək istəyirsinizsə java.math paketindəki(package-indəki) BigDecimal sinifini(class-ını) istifadə edə bilərsiniz. Fəqət xəbəriniz olsun ki, float və double-la olduğundan daha gec və daha böyük əməli yaddaş(RAM) xərciylə nəticələnəcək. IEEE 754 də bayaq dediyimiz tam, kəsr və “10 üstlü”-lərin tutduğu yerlərin miqdarlarının 32-64 bitlərə görə müəyyən edildiyi standartdır. 32-bit<span lang="EN-US">lilər</span> birqat dəqiqlikli(single-precision), 64-bit<span lang="EN-US">lilər isə</span> ikiqat dəqiqlikli(double-precision) <span lang="EN-US">kəsr ədədlər adlanırlar.</span> Java proqramlaşdırma dilinin yaradıcıları və dəstəkçiləri, uyğun olaraq, 32-bitlilərə uyğun qaydanı float-a, 64-bitlilərə uyğun qaydanı isə double-a tədbiq edirlər ki, bu qaydaların ədədlərlə ifadəsini aşağıdakı şəkildə görə bilərsiniz.</p> <p class="MsoNormal" style="margin-left: .5in">Şəkil 5:</p> <p class="MsoNormal" style="margin-left: .5in">Qeyd: Bütün işarələnmiş(signed) tiplərdə olduğu kimi float və double-da da ilk bit 0 olduqda ədəd müsbət, 1 olduqda isə mənfidir(həmin işarə - Sign). Exponent – “10 üstlülərimiz”, Fraction isə kəsr hissəsinə düşən paydır.</p> <p class="MsoNormal" style="margin-left: .5in"><img class="aligncenter size-full wp-image-26664" src="http://technet.az/wp-content/uploads/2016/12/32-64_bit_precision.png" alt="" width="407" height="116" /> </p> <p class="MsoNormal" style="margin-left: .5in">double – IEEE 754 standartlarına uyğun ikiqat dəqiqlikli, 64-bit ölçülü kəsr ədəddir.</p> <p class="MsoNormal" style="margin-left: .5in">boolean – bir-biriylə fikri ziddiyyət təşkil edən iki dəyərdən(true və false-dan) birini özündə saxlaya bilir. Ölçüsü JVM-dən (Java Virtual Machine-dən – compiler tərəfindən yoxlanıb-açıqlanılanılmaqla JVM-in özünün başa düşə biləcəyi hala salınan kodları icra edən virtual maşından) asılı olaraq dəyişdiyi üçün, dəqiq müəyyən oluna bilmir. Dediyim kimi, yalnız true və ya false dəyərlərini yadda saxlaya bilir.</p> <p class="MsoNormal" style="margin-left: 0.5in;text-align: left">char – bir hərf, bir rəqəm və ya hansısa bir xüsusi işarə (məs. !-=). Komputerlər characterləri(hərflər, rəqəmlər və xüsusi işarələri) klaviaturada yazıldığı kimi qəbul etmir. Məs. klaviaturada h klavişinə toxunduqda mərkəzi prosessora (CPU-ya) bir baytlıq 1101000 (104) kimi bir məlumat ötürülür. Hansı character-ə hansı ədədin aid olduğu isə biz insanlar və komputerlər üçün sabitdir və məlumdur. İnformasiya Mübadiləsi üçün Amerikan Standart Kodları(ASCII – <span>American Standart Code for Information Interchange) adlanan siyahıda ingilis dilinin hərfləri, rəqəmləri və həmin dildə işlənən xüsusi işarələr olmaqla cəmi 128 </span>(7-bitlik) simvol (char) var. Amma java təkcə ingilis dilinin deyil, eləcə də digər dillərdəki (məs. ə,ı, çin və s. dillərin simvolları kimi) simvolları əhatə edəcək bir “simvol yığını” (character set-i) – utf-16-nı (həm yazılan kodda (dəyişən adları, və s.), həm də char-ların dəyərlərində) dəstəkləyir ki, bu da 16-bitlik bir potensial - 65536 (2^16) sayda simvol vədd eləyir ([0; 65, 535], bu aralıqdakı ədədlərin hər biri bir simvolu işarə edir). char tipindəki dəyişənə hər hansı bir simvol tək dırnaqlar(‘) arasında mənimsədilir. Amma tək yol birbaşa simvolun özünü yazaraq mənimsətmək deyil. Tutaq ki, kodları yazdığınız mətn redaktoru, ya fayl sisteminiz, ya da hər ikisi yalnız (məs.) inglis dilində mövcud simvollarla işləməkdədir (simvollar yığınınız (character set-iniz) utf-16 -da deyil) və sizə verilmiş hansısa bir tapşırıq üçün (məs.) çin dilindəki bir simvola ehtiyac duydunuz. Cəmisi, bir simvola görə mətn redaktorunuz, ya fayl sisteminizdə, ya da hər ikisində dəyişiklik aparmaq əvəzinə hər hansısa mənbədən həmin simvolun unicode-unu tapıb tək dırnaqlar(‘) arasında \u dan sonra yaza bilərsiniz. \u -dan sonra 16-lı say sistemində yazılmış (hexadecimal) 4 ədəd olur (qeyd: mümkün halların sayı: 16^4 = 2^16 -dır (‘\u0000’(sözün əsl mənasında heç nə, boşluq yox ha, heçnə, qeyd: char c = ‘’; kompilyasiya xətasıdır(compilation error))-dan ‘\uffff’-ə qədər) ki, bu da char-ın ölçüsünü tam ödəyir).</p> <p class="MsoNormal" style="margin-left: .5in">Primitiv tiplər bu qədər. Ümumiləşdirməyə keçmədən String-lərə xəfif bir nəzər salaq: String istinad (reference) tiplərdəndir, <span style="color: red">primitiv deyil</span>. Bu tipdəki dəyişənə simvollar (char-lar) rahatlıqla “yüklənilə” bilər. Verilmiş simvollar silsiləsi String-ə qoşa dırnaqlar (“) arasında mənimsədilir (hətta, \u0000 tipli char-lar belə işlədilə bilir, tək dırnaqsız (‘) məs. aşağıdakı nümunədə konsol-a Rüstəm çap olunacaq. Qeyd: \u00FC – ü, \u0259 - ə hərfinə işarə edir.</p> <p class="MsoNormal" style="margin-left: .5in"> [java]</p> <p class="MsoNormal" style="margin-left: .5in">String s = “R\u00FCst\u0259m”;</p> <p class="MsoNormal" style="margin-left: .5in">System.out.println(s);</p> <p class="MsoNormal" style="margin-left: .5in">
). String tipindəki dəyişənə mənimsətmənin digər bir yolu da var. Ümid edirəm, bu mənimsətmələrin fərqlərini, işləmə mexanizimlərini növbəti məqalələrimizdən birində araşdırarıq.
Primitiv tiplər haqqında ümumi məlumatlar:
1. Bu primitiv tiplərin ”daldalandıqları”, ”söykənəcəkləri” – istinad (reference) tipləri var. Bunlar wrapper siniflər(wrapper classes) adlanır. Primitiv tipli dəyişənlər üzərindən çağırıla bilməyən tipin ümumi xassələri (property-ləri) və metodları bu wrapper siniflərdən (wrapper class-lardan) əldə edilə bilir. Şəkil 6:
Sabit dəyişənlər formasındakı xassələr:
BYTES – yadda saxlaya biləcəyi byte-ların sayı
SİZE – yadda saxlaya biləcəyi bit-lərin sayı
MİN_VALUE – mənimsədilə biləcək ən kiçik dəyər
MAX_VALUE – mənimsədilə biləcək ən böyük dəyər
TYPE (məs. int in wrapper sinfində (wrapper class-ında) bu dəyişən özü Class<Integer> tipindədir) – primitiv tipin wrapper sinifində (class-ında) mövcud olan xassələr (properties) və metodların adlarının siyahısı, və s. məlumatları özündə saxlayır.
2. Primitiv tipli dəyişənlərə mənimsədilən dəyərlər ya istifadəçilər tərəfindən daxil edilir yəni, kod-da yalnız həmin məlumatı verən dəyişən və metodlar adları görünür, ya da kodu yazan şəxs özü dəyərləri dəyişənlərə mənimsədir və ya mənimsətmədən hansısa məqsədlə istifadə edir ki, bu zaman həmin dəyərlər kodda görünür. İkinci seçimdəki dəyər ingilis dilli programlaşdırma ədəbiyyatında “literal” adlanır. Ənənəvi riyaziyyatdan tam ədəd olaraq tanıdığınız dəyərlər adi halda (default olaraq) int hesab olunur amma byte və short tipli dəyişənə də və sırf int-dən daha böyük aralığı əhatə etdiyindən int literal-ları long-a da mənimsədilə bilir. Məs. 14 long literalı deyil amma long a = 14; ifadəsi tamamilə doğrudur. Həqiqi long literal-ı yaratmaq üçün isə verilmiş literal-ın, daha doğrusu, dəyərin axrına l və ya L hərfi əlavə olunmalıdır. (Qeyd: l (kiçik “el” hərfi) yazılışına görə 1(bir) rəqəminə bənzədiyindən long literal-I yaratmaq üçün L(böyük “el” hərfi) işlətmək daha məqsədəuyğundur.) long int-dən geniş olduğundan, bəzən, bu long literal-larına ehtiyac duyulur. Tam ədədləri əhatə edən tiplər haqqında dediklərimizə bir istisna var. byte və ya short tipində parametr qəbul edən bir metod tam ədəd literalıyla çağırıla bilmir. Məs.
</p> <p class="MsoNormal" style="margin-left: .75in">byte b = 14;</p> <p class="MsoNormal" style="margin-left: .75in">short c = 14;</p> <p class="MsoNormal" style="margin-left: .75in">
kimi nümunələr doğrudur amma
</p> <p class="MsoNormal" style="margin-left: .75in">void metod(byte a) <span lang="EN-US">{}</span> </p> <p class="MsoNormal" style="margin-left: .75in">
kimi bir metod
</p> <p class="MsoNormal" style="margin-left: .75in">metod(14); </p> <p class="MsoNormal" style="margin-left: .75in">
kimi bir kodla çağırıla bilməz ki, bu məqamda 3 həll yolu mövcuddur:
a. Metodun parametrinin(a-nın) tipini int-ə və ya long-a dəyişmək:
int də, long da byte-dan və short-dan daha böyük yaddaş tutduğundan, və byte (və ya short) olaraq metodun bu parametrinin mənasının daha rahat anlaşıldığı halda (dəyişənin ölçüsü və adı bir yerdə həmin dəyişənin daşıdığı məlumat haqqında çox şey deyir) int və ya long-la bu “təmizlik” aradan qalxdığından bu yol xeyirdən çox ziyan gətirəcəkdir.
b. byte tipində bir dəyişən yaradıb 14-ü ona dərhal mənimsətmək, sonra həmin dəyişəni metoda parametr kimi ötürmək:
byte tipindəki artıq bir dəyişən əlavə 8 bit yaddaş deməkdir ki, daha yaxşı alternativ mövcud olduqda bu da yaxşı deyil. (qeyri-optimaldır)
c. Cast etmək. 14 dəyərinin qarşısına (byte) yazsaz: (bunun kimi: metod( (byte) 14); ) kodunuz java tərəfindən yoxlanılarkən (compile olunarkən) komputer parametrin byte tipində olduğundan əmin olur ki, bu da problemin ən optimal həlli deməkdir.
Kəsr ədədlər isə adi halda (default olaraq) double literal-ları olurlar. Yəni, 1.4 (məs.) bir double literalıdır. Yadınızdadırsa, adi halda int literalı long-a bu tiplərdən daha geniş olduğu üçün mənimsədilə bilirdi. (məs. long a = 5; ) float-lar üçün isə vəziyyət tam tərsinədir. float-ın ədəd aralığı double-ın ədəd aralığından daha kiçik olduğuna görə
float a = 1.4;
kimi bir kod nümunəsi xəta (kompilyasiya xətası – compilation error) verəcəkdir.(compilation error, exception kimi məsələlər geniş izah tələb etdiyindən bu məqalədə onların nə olduğu haqqında danışılmayacaq). float literal-ı yaratmaq üçün mənimsəniləcək kəsr dəyərin axrına f və ya F əlavə olunsa kifayətdir. (məs.
float a = 1.4f;
) Kəsr dəyərlərin axrına d və ya D əlavə olunsa, əlavə olunmadığında olduğu kimi olur – double literalı yaranır. Ancaq bir şeyi yaddan çıxarmayın ki, kəsr ədəd tipləri tam ədəd tiplərindən daha geniş olduğundan tam ədədlər heç bir cast (f-F,d-D əlavə olunaraq float və double literal-larının yaradılması, daha doğrusu, float və ya double-a çevrilmə) tələb etmədən float və ya double-a mənimsədilə bilir. Məs. aşağıdakı nümunələrin hamısı doğrudur: Şəkil 7:
</p> <p class="MsoNormal" style="margin-left: .5in">float f1 = 14;</p> <p class="MsoNormal" style="margin-left: .5in">double d1 = 14;</p> <p class="MsoNormal" style="margin-left: .5in">float f2 = 14L; </p> <p class="MsoNormal" style="margin-left: .5in">double d2 = 14L; </p> <p class="MsoNormal" style="margin-left: .5in">
Növbəti nümunələrin bəziləri doğru, bəziləri isə yanlışdır:
a.
</p> <p class="MsoNormal" style="margin-left: 63.0pt;text-indent: -.25in"><span style="text-indent: -0.25in">double d3 = 9223372036854775807;//yanlış</span></p> <p>
mənimsədilən dəyər int-in yadda saxlaya biləcəyi ən böyük dəyəri aşdığından literal özü yanlışdır!
b.
double d4 = 9223372036854775807L;//doğru
dəyər long-a cast olunub və long-un aralığını aşmadığından hər şey doğrudur.
c.
double d5 = 9223372036854775807999L;//yanlış
dəyər long-a cast olunub ancaq long-un aralığını aşdığından yanlışdır!
d.
double d6 = 9223372036854775807999d;//doğru
bayaqkı dəyər long-u aşırdı, amma double-ı aşmır, doğrudur.
Başqa bir məsələ də kalkulyatorlardan bizə tanış olan e -nin float və double-da işlədilə bilməsidir. Məs.
float a = 1.4e5f; double b = 1.4e5;
3. Java 2-li(binary – 0,1) , 8-li(octal – 0, 1, 2, 3, 4, 5, 6, 7), 10-lu(decimal – 0, 1, 2, 3, 4, 5, 6, 7, 8, 9) və 16-lı(hexadecimal – 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a-A, b-B, c-C, d-D, e-E, f-F) say sistemlərindəki ədəd literallarını dəstəkləyir. 2-lidə ədədin önünə 0b və ya 0B, 8-lidə 0, 10-luda heç nə(adi halda -default ədədlər sitemi), 16-lıda 0x və ya 0X əlavə olunur. (Qeyd: 0b-0B, 0, 0x-0X yazılarındakı 0 sıfırdır, [o] deyil) Nümunələr: Şəkil 8:
Qeyd: float-ın f-i(və ya F-i), double-ın d-si(və ya D-si) 16-lı say sistemindəki literal-larda təsirsiz qalır, daha doğrusu başqa məqsədə xidmət edir. Bu vəziyyətdəki f(və ya F) 16-lı sistemin 16-cı, d(və ya D) 15-cı nümayəndəsidir. (Xatırla: 16-lı say sisteminin üzvləri – 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a-A, b-B, c-C, d-D, e-E, f-F)
4. 2,147,483,647 2147483647-dən oxunarkən daha tez başa düşülür. Javada vergülün(,) xüsusi vəzifələri olduğundan həmin dilin qurucuları və dəstəkçiləri əvəzinə altdan xətti( _ ) bu iş üçün təyin ediblər. Bu altdan xəttin istifadəsində yalnız bir qayda var o da ki, həmin simvolun( _ ) yalnız iki ədəd(16-lı say sistemindəki a-A, b-B, c-C, d-D, e-E, f-F də daxil olmaqla) arasında işlədilə bilməsidir. Nümunələr:
Doğru kodlar- Şəkil 9:
Doğru və yanlış kodlar:
qeyd: invalid – yanlış, OK – doğru
// burada şərh (comment) yaratmaq üçün istifadə olunub, həmin simvoldan sətrin axrına qədər bütün yazılanları deaktiv edir. Şəkil 10:
5. Fərar simvolları – escape characters : \b, \t, \n, \f, \r, \”, \’, \\
Tutaq ki, sizə bir String-in içinə bir “(qoşa dırnaq) əlavə etmək gərək oldu. String s = “””; necə olar sizcə? Təbii ki, java kompilyatoru (java compiler) bundan “baş açmayıb”, kompilyasiya xətası (compilation error) verəcəkdir. Yuxarıdakı simvollardan bəziləri bu tipli qarışıqların həllini təmin edir, bəziləri isə String-lər içərisində hansısa başqa bir məqsədə xidmətlə məşğuldur:
a. \b – hansısa String literal-ında özündən əvvəlki bir simvolu(char-ı) silir. Məs. aşağıdakı nümunədə çıxış-da pul çap olunur.
String s = "pult\b"; System.out.println(s);
b. \t – tab . 4 məsafə-ni (space-i) əvəz edir. Məs. aşağıdakı nümunədə pul t çap olunacaq. System.out.println(“pul\tt”);
c. \n -line. Özündən sonrakı simvolları (char-ları) bir sətr aşağı atır. Məs. aşağıdakı nümunədə
pul
t
çap olunacaq: System.out.println(“pul\nt”);
d. \f – form feed. Java-da bu simvol ASCII dəyəri 12, unicode-u \u000C olan bir simvolu (üzü yuxarı şaquli oxu) işarə edir.
e. \r – carriage return. Hansısa String-də \r simvolundan (char-ından) sonra simvol(lar) gəlirsə həmin \r simvolunun olduğu sətr həmin simvola qədər silinir, yox əgər heç bir simvol yoxdursa, elə olduğu kimi qalır. Məs. aşağıdakı nümunədə t çap olunacaq:
System.out.println("pul\rt);
Növbəti nümunədə isə (abc silinib) pul çap olunacaq:
System.out.println(“pu\nabc\rl”);
Bunda isə pul çap olunanacaq:
System.out.println(“pul\r”);
f. \” bir qoşa dırnaq. Məs. aşağıdakı nümunədə pul”t çap olunacaq:
System.out.println("pul\"t);
h. \’ bir tək dırnaq. Məs. aşağıdakı nümunədə pul’t çap olunacaq
System.out.println("pul\'t");
i. \\- \. Aşağıdakı son nümunəmizdə isə pul\t çap olunacaq:
System.out.println("pul\\t");
Qeyd: “\” tək backslash kompilyasiya xətası (compilation error) səbəbidir.
6. Avtomatik mənimsədilən dəyərlər – default values:
Dəyər mənimsədilmədən bir dəyişəndən istifadə etməyə (dəyərini götürməyə) çalışsanız nə baş verəcək, sizcə? Kompilyasiya xətası (compilation error)? Həmişə yox. Bu məsələnin mahiyyətinə varmaq üçün gəlin əvvəlcə dəyişənləri 3 hissəyə bölək:
a. Lokal dəyişənlər (local variables)
b. Metod arqumenti (method arguments)
c. Nümunə və ya obyekt dəyişənləri (insance or non-static variables)
d. Sinif dəyişənləri (class or static variables)
Şəkil 11:
a. Nümunədə dəyişən1-in altındakı qırmızı dalğalı xətdən də anlaşıldığı kimi heç bir dəyər mənimsədilmədən lokal dəyişənlərin dəyərlərinin çağırılması – lokal dəyişənlərin işlədilməsi kompilyasiya xətasıyla (compilation error-la) nəticələnir.
b. dəyişən2 – metod arqumentidir və adından da anlaşıla biləcəyi kimi metod çağırılarkən verilən dəyəri özündə saxlayır. Məs. metod(5); kimi bir kodla çağırılarkən artıq dəyişən2-yə 5 dəyəri mənimsədilmiş olur ki, avtomatik mənimsətməyə ehtiyac da yoxdur.
c. dəyişən3 – nümunə və ya obyekt dəyişənidir ki, nümunənin (obyektin) xassələrinin dəyərinin olması, məntiqi cəhətdən, bütün nümunələr (obyektlər) üçün vacib olduğundan proqramçılar eyni işlərlə təkrarən məşğulluqla vaxt itirməsinlər deyə əgər nümunələrə(obyekt-lərə) özümüz dəyər mənimsətməsək, java kompilyatoru (java compiler) avtomatik nümunə (obyekt) dəyişənlərinə hansısa məna ifadə edən, düşünülərək seçilmiş müəyyən dəyərlər mənimsədir.
d. dəyişən4 kimi statik və ya sinif dəyişənlər isə sinifin (class-ın) özü və eyni zamanda bütün nümunələrinə (obyektlərinə) aid ümumi xassələr daşıyır ki, bu vəziyyətdə də nümunə (obyekt) dəyişənlərində olduğu kimi, həmin xassələrin “boş qalmaması” (mənimsədilməmiş qalmaması) vacibdir və yenə, sinif və ya statik dəyişənlərinə əgər özümüz dəyər mənimsətməsək, java kompilyatoru (java compiler) avtomatik hansısa məna ifadə edən, düşünülərək seçilmiş müəyyən dəyərlər mənimsədir.
Nəticədə, avtomatik mənimsətmə (default initialization) yalnız nümunə(obyekt) və sinif(statik) dəyişənlərinə aid edilir.
Yaxşı hansı tip dəyişənə hansı dəyər?
Bütün ədəd tiplərinə 0, char-a sözün əsl mənasında heç nə – ‘\u0000’, boolean-a məntiqlə 0-a analoq olan false, String və digər istinad (reference) tiplərinə isə heç nəni ifadə edən bir dəyər – null mənimsədilir. Şəkil 12:
Ümid edirəm, primitiv məlumat tipləri barəsində ətraflı araşdırmaların nəticəsi olan bu məqaləm sizə yararlı olar.
İstinadlar:
1. https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
2. http://www.java2s.com/Tutorials/Java/Java_Data_Type/0160__Java_Unsigned_Data_Type.htm
3. http://www.ntu.edu.sg/home/ehchua/programming/java/datarepresentation.html
4. https://en.wikipedia.org/wiki/Category:Dynamically_typed_programming_languages
5. https://en.wikipedia.org/wiki/Category:Statically_typed_programming_languages
6. https://stackoverflow.com/questions/3091524/what-are-carriage-return-linefeed-and-form-feed
8. İstifadə edilmiş bir neçə termin:
Kitabın adı: İnformatikanın əsasları
Müəlliflər: İsa Musayev, Mətləb Əlizadə, Mirzə Əhmədov, Gülşən Fərhadova
Səda nəşriyyatı
İSBN: 5-86874-156-0
Qeyd: M.F. Axundzadə adına Azərbaycan Milli Kitabxanasında pulsuz mütaliə edə bilərsiniz.
Şərhlər ( 1 )
Məqaləni sayta daxil edərkən İŞARƏLƏNMİŞ(SİGNED) ƏDƏD TƏQDİMATINDA yazı səhvlərinə yol vermişəm: