1. Baza sinfin metodlarını çağırmaq üçün super-dən istifadə
Siz subklass yaradanda bəzən baza sinfin sahə və ya metodlarına müraciət etmək lazım olur, xüsusən onları yenidən təyin etdikdə (override) və ya kölgələdikdə (gizlətdikdə). Bunun üçün Java-da xüsusi açar söz var — super.
Oxşarlıq üçün belə deyək: super — bu, «ana, kömək et!» kimidir; yəni subklassda valideyndə müəyyən edilmiş şeyə açıq şəkildə müraciət etmək istəyəndə istifadə olunur.
Tutaq ki, sizdə Animal sinfi var və eat() metodu sadəcə "Heyvan yeyir" çap edir. Cat sinfində isə istəyirsiniz ki, pişik əvvəlcə özünəməxsus nəsə etsin (məsələn, miyovlasın), sonra isə yenə də standart «heyvan yeyir» yerinə yetirilsin. Bax, elə burada super.eat() köməyə gəlir.
Subklassda metodu yenidən təyin etdikdə, amma onun daxilində baza sinfin eyni metodunun reallaşdırılmasını da çağırmaq istəyəndə, super.methodName() istifadə edin.
Nümunə: davranışı genişləndiririk
class Animal {
void eat() {
System.out.println("Heyvan yeyir");
}
}
class Cat extends Animal {
@Override
void eat() {
System.out.println("Pisik yeməyi iyləyir...");
super.eat(); // Animal sinfindən eat() metodunu çağırırıq
System.out.println("Pisik məmnun halda mırıldanır");
}
}
Bu necə işləyir?
- Cat tipli obyekt üçün eat() çağırılanda, əvvəlcə Cat.eat() daxilindəki kod, yəni öz metodumuz icra olunur.
- Bu metodun içində biz açıq şəkildə super.eat() — yəni valideyn Animal sinfinin reallaşdırmasını çağırırıq.
- Bu, «valideyn» davranışını unutmadan əlavə funksionallıq qatmağa imkan verir.
Təcrübə: tətbiqdə istifadə edirik
Tutaq ki, tədris tətbiqimizdə baza sinfi Animal və subklasslar Dog və Cat var. İstəyirik ki, heyvanı yemləyərkən həm ümumi hərəkətlər (məsələn, toxluğun artması), həm də hər bir heyvana xas olan spesifik davranış icra olunsun.
class Animal {
int satiety = 0;
void eat() {
satiety += 10;
System.out.println("Heyvan yeyir. Toxluq: " + satiety);
}
}
class Dog extends Animal {
@Override
void eat() {
System.out.println("It yeməkdən əvvəl quyruğunu yelləyir");
super.eat();
}
}
İndi dog.eat() çağırdıqda, hər iki mesajı görəcəksiniz və satiety düzgün artacaq.
2. Baza sinfin sahələrinə çıxış üçün super-dən istifadə
Əgər subklassda valideyn sinifdəki ilə eyni ada malik sahə elan etmisinizsə, o, valideynin sahəsini «kölgələyir». Bəzən baza sinfin orijinal sahəsinə çıxış etmək lazımdır — bunun üçün super.fieldName istifadə olunur.
Nümunə: sahənin kölgələnməsi
class Animal {
String name = "Heyvan";
}
class Cat extends Animal {
String name = "Pisik";
void printNames() {
System.out.println("Cat-dan ad: " + name);
System.out.println("Animal-dan ad: " + super.name);
}
}
new Cat().printNames(); çağırışı belə çıxış verəcək:
Cat-dan ad: Pisik
Animal-dan ad: Heyvan
Real praktikanın özündə sahələri «kölgələmək» zəruri olmadıqca tövsiyə edilmir, amma belə bir imkanın mövcud olduğunu bilmək faydalıdır.
3. Baza sinfin konstruktorunu super(...) ilə çağırmaq
Obyektlər iyerarxiyada necə yaradılır?
Subklassın obyektini yaratdığınızda, əvvəl baza sinfinin konstrukturu, daha sonra isə subklassın konstrukturu çağırılır. Bu, bütün sahələrin düzgün ilkinləşdirilməsi üçün lazımdır, çünki subklass valideyndən vəziyyətin (state) bir hissəsini «irsi» alır.
Baza sinfin konstruktorunu açıq şəkildə çağırmaq
Əgər baza sinfində parametrsiz konstruktor varsa — hər şey sadədir: Java subklassın konstruktoru icra olunmazdan əvvəl onu özü çağıracaq. Amma valideyndə parametrsiz konstruktor yoxdursa, uyğun konstruktoru super(...) vasitəsilə açıq şəkildə çağırmağa məcbursunuz.
Nümunə:
class Animal {
String name;
Animal(String name) {
this.name = name;
System.out.println("Heyvan yaradıldı: " + name);
}
}
class Cat extends Animal {
Cat(String name) {
super(name); // mütləqdir! Parametrsiz Animal() konstruktoru yoxdur
System.out.println("Pisik yaradıldı: " + name);
}
}
new Cat("Murka") çağırışı belə çap edəcək:
Heyvan yaradıldı: Murka
Pisik yaradıldı: Murka
Vacibdir: Valideynin konstruktorunu super(...) ilə çağırmaq subklassın konstruktorunda birinci sətir olmalıdır. Əgər bu çağırışdan əvvəl nəsə yazmağa cəhd etsəniz, kompilyator narazı qalacaq və bunu sizə xatırladacaq.
Açıq şəkildə çağırmasanız?
Əgər valideyndə yalnız parametrlərlə konstruktor varsa və siz onu super(...) ilə açıq şəkildə çağırmadınızsa, kompilyator səhv verəcək: "constructor Animal in class Animal cannot be applied to given types".
4. Faydalı incəliklər
super nə vaxt istifadə olunmalıdır?
Davranışı əvəzləmək yox, genişləndirmək üçün.
Bəzən metodu tam əvəzləmək yox, onu sadəcə «genişləndirmək» istəyirsiniz. Məsələn, valideyn məntiqindən əvvəl və ya sonra nəyisə əlavə etmək. Belə hallarda yenidən təyin edilmiş metodun içində super.methodName() istifadə edin.
İrsən alınmış sahələrin ilkinləşdirilməsi üçün.
Əgər valideyndə mütləq ilkinləşdirilməli sahələr varsa (məsələn, heyvanın adı), uyğun parametrlərlə valideynin konstruktorunu super(...) vasitəsilə mütləq çağırın.
Gizlədilmiş sahə/metodlara çıxış üçün.
Hər hansı səbəbdən valideynin sahəsini və ya metodunu «kölgələmisinizsə» və yenə də ona müraciət etmək lazımdırsa, super.fieldName və ya super.methodName() istifadə edin.
super-in istifadəsinin məhdudiyyət və xüsusiyyətləri
- Valideyn konstruktorunu super(...) ilə çağırmaq yalnız konstruktor daxilində və yalnız birinci sətirdə mümkündür.
- Valideynin konstruktorunu subklassın konstruktordan kənarda çağırmaq olmaz.
- super(...) açıq çağırılmasa, Java valideynin parametrsiz konstruktorunu (əgər varsa) çağırmağa çalışacaq.
- super açar sözünü statik metodlarda istifadə etmək olmaz — yalnız qeyri-statik (obyekt) metodlarda və konstruktorlarda istifadə oluna bilər.
- Əgər valideynin metod və ya sahəsi private-dırsa, super kömək etməyəcək: özəl (private) üzvlərə çıxış yoxdur.
5. Möhkəmləndirici nümunələr
Nümunə 1. Metodu super ilə genişləndiririk
class Animal {
void makeSound() {
System.out.println("Heyvan səs çıxarır");
}
}
class Dog extends Animal {
@Override
void makeSound() {
super.makeSound(); // əvvəl standart hərəkəti edirik
System.out.println("It hürür: Hav-hav!");
}
}
Nümunə 2. Baza sinfin konstruktorunu çağırmaq
class Vehicle {
String brand;
Vehicle(String brand) {
this.brand = brand;
System.out.println("Nəqliyyat vasitəsi: " + brand);
}
}
class Car extends Vehicle {
int year;
Car(String brand, int year) {
super(brand); // valideynin konstruktorunu çağırırıq
this.year = year;
System.out.println("Avtomobil " + brand + ", il: " + year);
}
}
Car car = new Car("Toyota", 2023);
// Çıxış:
// Nəqliyyat vasitəsi: Toyota
// Avtomobil Toyota, il: 2023
Nümunə 3. Klassik səhv: super(...) çağırmağı unutmaq
class Animal {
String name;
Animal(String name) {
this.name = name;
}
}
class Cat extends Animal {
Cat() {
// super(); // Səhv! Parametrsiz Animal() konstruktoru yoxdur
// Aydın şəkildə super(name) çağırmaq lazımdır
super("Adsız pişik");
}
}
6. super ilə işləyərkən tipik səhvlər
Xəta № 1: super(...) çağırışı konstruktorun birinci sətri deyil.
Java tələb edir ki, valideynin konstruktorunu super(...) ilə çağırmaq subklassın konstruktorunda birinci sətir olsun. Əgər bu çağırışdan əvvəl nəsə etməyə cəhd etsəniz (məsələn, mesaj çap etmək), kompilyator səhv verəcək.
Xəta № 2: Valideyndə uyğun konstruktor yoxdur.
Əgər baza sinfində parametrsiz konstruktor yoxdur və siz başqa konstruktoru super(...) ilə çağırmadınızsa, kompilyator standart çağırış yarada bilməyəcək və səhv bildirəcək.
Xəta № 3: Valideynin özəl (private) üzvlərinə super vasitəsilə müraciət cəhdi.
super açar sözü valideynin özəl sahə və ya metodlarına sehrli çıxış vermir. Nəsə private kimi elan olunubsa, subklass üçün əlçatmaz qalır.
Xəta № 4: Sahə və metodların düşünmədən kölgələnməsi.
Subklassda valideynlə eyni adlı sahə və ya metod elan etmisinizsə və bunu unutmusunuzsa, gözlənilməz nəticələr mümkündür. Belə halda valideyn üzvünə çıxış — yalnız super vasitəsilədir.
Xəta № 5: super-dən statik metodda istifadə.
Statik metodlarda super istifadə etmək olmaz, çünki onlar konkret obyektə məxsus deyil.
GO TO FULL VERSION