1. Java-da obyektlərin müqayisəsi
Java-da obyektləri həm istinad, həm də dəyərə görə müqayisə etmək olar.
İstinadların müqayisəsi
Əgər iki dəyişən yaddaşda eyni obyektə işarə edirsə, o zaman bu dəyişənlərdə saxlanan istinadlar bərabərdir. Əgər bu dəyişənləri ==
bərabərlik operatoru ilə müqayisə etsək, nəticədə true alınacaq, bu da məntiqidir. Burada hər şey sadədir.
Kod | Ekrana çıxış |
---|---|
|
|
Dəyərə görə müqayisə
Amma tez-tez belə bir vəziyyətə rast gəlmək olar ki, iki dəyişən fərqli, amma eyni obyektlərə işarə edir. Məsələn, eyni mətni saxlayan, amma fərqli obyektlərdə yerləşən iki sətir.
Fərqli obyektlərin eyniliyini müəyyən etmək üçün equals()
metodundan istifadə etmək lazımdır. Misal:
Kod | Ekrana çıxış |
---|---|
|
|
equals
metodu təkcə String
sinifində mövcud deyil — bu metod bütöv bütün siniflərdə var.
Hətta siz yazacağınız siniflərdə də, və səbəbi də budur.
2. Object
sinfi
Java-da bütün siniflər Object
sinifindən irsən gəlmiş hesab olunur. Java-nın yaradıcıları bunu belə düşünüb.
Əgər bir sinif Object
sinifindən irsən gəlmişdirsə, bu irsi qəbul etmiş sinifdə Object
sinfinin bütün metodları avtomatik olaraq mövcud olur. Bu, irsiyyətin əsas xüsusiyyətidir.
Başqa sözlə, hər bir sinifdə, hətta kodunda bu göstərilməsə belə, Object
sinfindəki bütün metodlar mövcuddur.
Bu metodlar arasında obyektlərin müqayisəsi ilə əlaqəli metodlar da var. Bunlar equals()
və hashCode()
metodlarıdır.
Kod | Necə olacaq: |
---|---|
|
|
Yuxarıdakı nümunədə biz name
və age
parametrləri ilə bir sadə Person
sinfi yaratdıq, heç bir metod olmadan. Amma, bütün siniflər Object
sinfindən irsən gəldiyi üçün Person
sinfində iki gizli metod var:
Metod | Təsvir |
---|---|
|
Mövcud obyekt ilə ötürülən obyekti müqayisə edir |
|
Mövcud obyektin hash-code qaytarır |
Belə çıxır ki, equals
metodları tamamilə bütün obyektlərdə mövcuddur və müxtəlif tiplərdəki obyektlər bir-biri ilə müqayisə edilə bilər, və bu mükəmməl şəkildə kompilyasiya olunub işləyəcək.
Kod | Ekranda çıxış |
---|---|
|
|
|
|
3. equals()
Metodu
Object
sinifindən miras alınan equals()
metodu, mövcud və ötürülən obyektləri müqayisə etmək üçün ən sadə alqoritmi ehtiva edir — sadəcə onların istinadlarını müqayisə edir.
Eyni effekt Person
sinfinin dəyişənlərini bir-birinə müqayisə etməklə əldə edilir, equals()
metodunu çağırmağa ehtiyac yoxdur. Məsələn:
Kod | Ekrana çıxış |
---|---|
|
|
equals
metodu sadəcə içərisində a
və b
istinadlarını müqayisə edir.
Ancaq String
sinifində müqayisə fərqli işləyir. Niyə?
Çünki String
sinfinin yaradıcıları equals()
metodunun öz implementasiyasını yazıblar.
equals()
metodunun implementasiyası
Gəlin, Person
sinfində equals
metodunun öz implementasiyasını yazaq. 4 əsas ssenarini nəzərdən keçirək.
equals
metodu yenidən müəyyən edildiyində, o həmişə
Object
tipli parametr qəbul edir.
Ssenari 1: equals
metoduna eyni obyekt ötürülüb, hansında ki equals
metodu çağırılıb. Əgər mövcud və ötürülən obyektlərin istinadları bərabərdirsə, true
qaytarılmalıdır. Obyekt özü ilə üst-üstə düşür.
Kodda bu belə görsənəcək:
Kod | Təsvir |
---|---|
|
İstinadları müqayisə edirik |
Ssenari 2: equals
metoduna null
istinadı ötürülüb — müqayisə edəcək heç nə yoxdur. equals
metodunun çağırıldığı obyektin null olmadığı dəqiqdir, beləliklə, bu halda false
döndürmək lazımdır.
Kodda bu belə görünəcək:
Kod | Təsvir |
---|---|
|
İstinadları müqayisə edirik Ötürülən obyekt — null ? |
Ssenari 3: equals
metoduna ümumiyyətlə Person
sinfinə aid olmayan obyekt ötürülüb. Person
sinfinin obyekti qeyri-Person
sinfinin obyekti ilə bərabərdir? Burada artıq qərarı Person
sinfinin tərtibçisi verir — öz istəyinə uyğun şəkildə həyata keçirir.
Ancaq adətən, obyektlər bir sinifdən olduğu halda bərabər sayılır. Buna görə də, əgər bizim equals
metoduna Person
sinfinə aid olmayan bir obyekt ötürülübsə, həmişə false
qaytaracağıq. Obyektin hansı tipdən olduğunu necə yoxlamaq olar? Düzdür: instanceof
operatoru vasitəsilə.
Bizim yeni kodumuz belə görünəcək:
Kod | Təsvir |
---|---|
|
İstinadları müqayisə edirik Ötürülən obyekt — null ? Əgər ötürülən obyekt Person tipində deyilsə |
4. İki Person
obyektinin müqayisəsi
Nəticədə biz nə əldə etdik? Əgər metodun sonuna qədər çatmışıqsa, deməli, bizdə Person
tipində obyekt və link null
deyil. O zaman onu Person
tipinə çeviririk və hər iki obyektin daxili hissələrini müqayisə edirik. Bu, bizim 4-cü ssenarimizdir.
Kod | Təsvir |
---|---|
|
Linkləri müqayisə edirik Keçirilən obyekt — null ? Əgər keçirilən obyekt Person tipində deyilsə Tip çevrilməsi əməliyyatı |
Bəs iki Person
obyektini necə müqayisə edirik? Onlar yalnız adları (name
) və yaşları (age
) eynidirsə, bərabər hesab olunurlar. Son kod belə görünəcək:
Kod | Təsvir |
---|---|
|
Linkləri müqayisə edirik Keçirilən obyekt — null ? Əgər keçirilən obyekt Person tipində deyilsə Tip çevrilməsi əməliyyatı |
Amma bu hələ də hamısı deyil.
Birincisi, name sahəsinin tipi String
-dir, ona görə də name sahələrini equals
metodunu çağıraraq müqayisə etmək lazımdır.
this.name.equals(person.name)
İkincisi, name
sahəsi null
ola bilər: o halda, onun üzərində equals
metodunu çağırmaq mümkün deyil. null
üçün əlavə yoxlama lazımdır:
this.name != null && this.name.equals(person.name)
Lakin əgər hər iki Person
obyektində name null
-dırsa, onda adlar yenə də bərabər hesab olunur.
Dördüncü ssenarinin kodu, məsələn, belə görünə bilər:
|
Əgər yaşlar fərqlidirsə, dərhal return false Əgər this.name null -dırsa, equals ilə müqayisə etməyə ehtiyac yoxdur. Burada ya ikinci sahə name null -dır, ya da deyil. Iki name sahəsini equals ilə müqayisə edirik. |
5. hashCode()
Metodu
equals
metodundan başqa, hansı ki, hər iki obyektin bütün tarlalarını detal olaraq müqayisə edir, başqa bir metod da var ki, dəqiq olmasa da çox sürətli müqayisə etmək üçün istifadə olunur — bu hashCode()
metodudur.
Təsəvvür edin ki, siz yüzlərlə sözdən ibarət bir siyahını əlifba sırasına görə sıralayırsınız və hər dəfə cüt olaraq sözləri müqayisə etməlisiniz. Amma sözlər uzundur və çox hərf ehtiva edir. Ümumiyyətlə, belə bir müqayisə çox vaxt aparacaq.
Ancaq bunu sürətləndirmək olar. Deyək ki, sözlər fərqli hərflərlə başlayır: dərhal aydındır ki, onlar fərqlidir. Amma eyni hərflə başlayırlarsa, zəmanət yoxdur: sonradan sözlər həm eyni, həm də fərqli ola bilər.
hashCode()
metodu bənzər prinsipi tətbiq edir. Əgər onu obyektə çağırsaq, o, müəyyən bir rəqəm qaytaracaq — bu, sözün ilk hərfi analoqudur. Bu rəqəm belə xüsusiyyətlərə malikdir:
- Eyni obyektlərdə həmişə eyni hash-code olur
- Fərqli obyektlərdə eyni hash-code ola bilər, fərqli də ola bilər
- Əgər obyektlərin hash-code fərqlidirsə, obyektlər dəqiq fərqlidir
Daha yaxşı başa düşmək üçün bu xüsusiyyətləri sözlərə aid olaraq yenidən yazaq:
- Eyni sözlərdə həmişə eyni birinci hərflər olur
- Fərqli sözlərdə eyni birinci hərf ola bilər, fərqli də ola bilər
- Əgər sözlərin birinci hərfləri fərqlidirsə, sözlər dəqiq fərqlidir
Sonuncu xüsusiyyət obyektləri sürətli müqayisə etmək üçün istifadə olunur:
Əvvəlcə iki obyektin hash-code-ları hesablanır. Əgər bu hash-code-lar fərqlidirsə, obyektlər dəqiq fərqlidir və onları daha da müqayisə etməyə ehtiyac yoxdur.
Amma əgər hash-code-lar eynidirsə, obyektləri equals vasitəsilə yenə də müqayisə etmək lazım olur.
6. Kodda müqavilələr
Yuxarıda təsvir edilən davranışı bütün Java sinifləri həyata keçirməlidir. Obyektlərin müqayisəsinin düzgünlüyünü kompilasiya səviyyəsində yoxlamaq mümkün deyil.
Bütün Java proqramçıları razılaşıblar ki, əgər standart metodun (sinif Object
-dən) əvəzinə öz equals() metodlarını yazırlarsa, həmin qaydaları qorumaq üçün həmçinin öz hashCode() metodlarını da yazmalıdırlar.
Bu razılaşma müqavilə adlanır.
Əgər sinifinizdə yalnız equals() metodunun və ya yalnız hashCode() metodunun realizasiyasını əlavə etsəniz, müqaviləni (razılaşmanı) pozmuş sayılırsınız. Belə etmək olmaz.
Əgər digər proqramçılar sizin kodunuzu istifadə etsə, o düzgün işləməyə bilər. Həmçinin, siz özünüz də yuxarıda göstərilən müqavilələr əsasında işləyən koddan istifadə edəcəksiniz.
Java-da bütün kolleksiyalar qiymət axtarışı zamanı əvvəlcə obyektlərin hash-code-nu müqayisə edir, sonra isə müqayisə üçün equals metodunu çağırır.
Ona görə də əgər öz sinifinizi yazsanız və orada yeni equals funksiyasını yaratsanız, amma hashCode() metodunu yazmasanız və ya onu səhvlə realizə etsəniz, kolleksiyalar sizin obyektlərinizlə düzgün işləyə bilməz.
Məsələn, siz obyekti siyahıya əlavə edirsiniz, sonra onu contains() metodu ilə axtarırsınız, amma kolleksiya sizin obyektinizi tapa bilmir.
GO TO FULL VERSION