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