CodeGym /Kurslar /JAVA 25 SELF /Anonim siniflər

Anonim siniflər

JAVA 25 SELF
Səviyyə , Dərs
Mövcuddur

1. Anonim siniflərlə tanışlıq

Təsəvvür et ki, səndə Animal sinfi var və o, heyvanın necə davrandığını təsvir edir. Bu sinfin say() metodu var və o, "Heyvan səs çıxarır" çap edir. Sənə it kimi davranan və "Hav!" çap edən obyekt yaratmaq lazımdır, amma bunun üçün ayrıca Dog.java faylı yaratmaq istəmirsən.

Burada köməyimizə anonim siniflər gəlir. Bunlar adı olmayan, istifadəsi zamanı birbaşa elan olunan və yaradılan siniflərdir. 🚀 Onlar sinfi “yerindəcə” miras almağa imkan verir, ayrıca fayl yaratmadan. Ayrı-ayrı yerlərdə cəmi bir dəfə istifadə olunan kiçik siniflər üçün çoxlu fayllar yaratmaq əvəzinə, bütün məntiqi elə lazım olan yerdəcə yaza bilərsən.

Sintaksis necə görünür?

Anonim siniflərin sintaksisi qeyri-adi görünə bilər, amma əslində kifayət qədər sadədir:

TipPeremennoy imya = new TipDlyaNasledovaniya() {
    // Burada anonim sinifin bədənini yazırıq
    // Valideyn sinfin metodlarını yenidən təyin edirik (override)
};

Gəlin bu sintaksisi izah edək:

  • TipPeremennoy imya: Yeni obyektimizi saxlayacağımız adi dəyişən elanı.
  • new TipDlyaNasledovaniya(): Sanki yeni obyekt yaradırıq. Amma sinif adı kimi miras almaq istədiyimiz sinifin adını istifadə edirik. Nəzərə al ki, () mötərizələrindən sonra nöqtəli vergül yoxdur!
  • { ... }: Burada fiqurlu mötərizələri açırıq və anonim sinifimizin bütün məntiqini yazırıq. Valideyn sinfin metodlarını yenidən təyin edə və ya öz məntiqimizi əlavə edə bilərik.

Adi sinifdən miras alma nümunəsi:

Heyvan nümunəmizə qayıdaq.

class Animal {
    void say() {
        System.out.println("Heyvan səs çıxarır");
    }
}

// Animal-dan miras alaraq anonim sinif yaradırıq
Animal dog = new Animal() {
    // say() metodunu yenidən təyin edirik
    @Override
    void say() {
        System.out.println("Hav-hav! 🐶");
    }
};

Animal cat = new Animal() {
    @Override
    void say() {
        System.out.println("Miyau-miyau! 🐱");
    }
};

dog.say(); // Çap edəcək: Hav-hav! 🐶
cat.say(); // Çap edəcək: Miyau-miyau! 🐱

Bu nümunədə biz iki obyekt — dogcat — yaratdıq; bunlar mahiyyətcə Animal-dan miras alan anonim siniflərdir. Üstəlik, ayrıca bir fayl belə yaratmadıq.

Yanaşmaların müqayisəsi

// Adi üsul (ayrı sinif yaradırıq)
class Dog extends Animal {
@Override
void say() { System.out.println("Hav!"); }
}
Animal dog = new Dog();

// VS

// Anonim sinif (hər şey bir məkanda)
Animal dog = new Animal() {
@Override
void say() { System.out.println("Hav!"); }
};

Nəticə eynidir, amma anonim sinif daha qısadır və layihəni çirkləndirmir!

2. Kompilyasiyadan sonra anonim sinifin adı

Anonim siniflərin mənbə kodunda adı yoxdur, amma Java kompilyatoru əlbəttə ki, .class-fayl yaratmaq üçün onları hansısa qaydada adlandırmalıdır. O, bunu ciddi müəyyən olunmuş qaydaya əsasən edir:

  • Anonim sinifin fayl adı onun elan olunduğu xarici sinifin adından ibarət olur.
  • Xarici sinifin adından sonra $ işarəsi əlavə olunur.
  • Daha sonra həmin fayldakı anonim sinifin sıra nömrəsi gəlir və 1-dən başlayır.

Beləliklə, heyvanlarla bağlı nümunəmiz Main.java faylındadırsa, kompilyasiyadan sonra üç fayl yaradılacaq:

  • Main.class
  • Main$1.class (it üçün anonim sinifimiz)
  • Main$2.class (pişik üçün anonim sinifimiz)

Əgər anonim sinif daxil sinifin içində olan metod daxilində elan olunubsa, ad daha mürəkkəb görünəcək, məsələn, OuterClass$InnerClass$1.class.

Bu, kompilyatorun daxili razılaşmasıdır — bilmək faydalıdır, amma gündəlik inkişafda nadir hallarda mühüm rol oynayır. Əsas odur ki, anonim sinif mənbə kodunda adı olmasa belə, tamhüquqlu sinifdir.

3. Vacib xüsusiyyətlər və məhdudiyyətlər

Anonim siniflər güclü alətdir, lakin onların öz qaydaları var.

Dəyişənlərə çıxış. Anonim sinif onu əhatə edən metodun dəyişənlərindən istifadə edə bilər. Lakin bu dəyişənlər final və ya effectively final olmalıdır (yəni dəyəri inisializasiyadan sonra dəyişməməlidir).

public void doSomething() {
    String greeting = "Salam!"; // Bu dəyişən effectively final-dır

    class OuterClass {
        void greet() {
            // Metodun içində anonim sinif yaradırıq
            new Object() {
                void sayHello() {
                    System.out.println(greeting); // Bu icazəlidir
                    // greeting = "Hələlik!"; // Bu isə xəta verəcək!
                }
            }.sayHello();
        }
    }

    new OuterClass().greet();
}

Niyə belədir? Çünki anonim sinif metoddan daha uzun “yaşaya” bilər və əgər o, dəyişəni dəyişə bilsəydi, bu, problemlərə səbəb olardı.

Konstruktor yoxdur. Anonim sinifin adı olmadığı üçün onun konstrukturu da ola bilməz. Amma obyekt yaradılarkən kod icra etmək üçün inisializasiya blokundan istifadə edə bilərsən:

Animal dog = new Animal() {
    // İnisializasiya bloku
    {
        System.out.println("Anonim sinifin inisializasiyası 🐶");
    }
    @Override
    void say() {
        System.out.println("Hav-hav!");
    }
};

Məhdudiyyətlər. Anonim siniflər statik sahələr (konstantalar istisna olmaqla) və ya metodlar elan edə bilməz. Onlar həmişə başqa bir obyektin tərkibində yaradılır, buna görə də static, public, protected və ya private ola bilməzlər.

4. Faydalı nüanslar

Anonim sinifləri nə vaxt istifadə etməli

  • Bir sinfi (və ya interfeysi) cəmi bir dəfə miras almaq (və ya reallaşdırmaq) lazımdırsa.
  • Reallaşdırma kiçikdir — 1–2 metod, bir neçə on sətirdən artıq deyil.
  • Sinif yalnız bir yerdə lazımdır və ona ad verməyin mənası yoxdur.
  • Paketin birdəfəlik kiçik siniflərlə “zibilə” çevrilməsinin qarşısını almaq istəyirsiniz.

Tipik ssenarilər:

  • Hadisə emalçıları (GUI, Swing, Android və s.).
  • Metodlara callback-lərin ötürülməsi.
  • Kolleksiyaların çeşidlənməsi üçün komparatorların tez yazılması.
  • Müvəqqəti dəyişdirilmiş obyektlər (məsələn, testlər üçün).

5. Xarici siniflə qarşılıqlı əlaqə

Əgər anonim sinif xarici sinifin qeyri-statik metodu və ya bloku daxilində elan olunarsa, o, həmin xarici sinifin sahə və metodlarına (hətta private olanlara belə!) müraciət edə bilər.

public class Outer {
    private String secret = "Gizli mətn";

    // Baza sinfi
    class Printer {
        public void print() {
            System.out.println("Adi çıxış");
        }
    }

    public void revealSecret() {
        Printer p = new Printer() {
            @Override
            public void print() {
                System.out.println("private sahəyə çıxış: " + secret);
            }
        };
        p.print();
    }

    public static void main(String[] args) {
        new Outer().revealSecret();
    }
}

6. Anonim siniflərlə işləyərkən tipik səhvlər

Səhv №1: əhatə edən metoddakı dəyişəni dəyişməyə cəhd.
Dəyişəni anonim sinifdən kənarda elan etmisinizsə və onu anonim sinif daxilində istifadə etdikdən sonra dəyişməyə çalışsanız — kompilyator xəta verəcək. Dəyişən final və ya effectively final olmalıdır (inisializasiyadan sonra dəyişməməlidir).

Səhv №2: həddindən artıq böyük anonim sinif.
Əgər anonim sinif onlarla sətrə qədər böyüyüb və bir neçə metoddan ibarətdirsə — onu ayrıca adlı sinifə çıxarmağın vaxtıdır. Əks halda kod oxunmaz olacaq.

Səhv №3: statik metod və ya sahələrdən istifadə cəhdi.
Anonim sinifdə statik metod və ya sahələr elan etmək olmaz (konstantalar istisna). Əgər buna həqiqətən ehtiyac varsa — adi daxili sinif yazın.

Səhv №4: görünürlük (scope) barədə unutmaq.
Anonim sinif yalnız elan olunduğu yerdə görünür və onun adı yoxdur. Təkrar istifadə lazımdırsa — adi sinif elan edin.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION