1. Giriş
Java-da giriş modifikatorları — evdəki kilid sistemi kimidir. Onlar kimin və haradan sizin otağınıza (və ya sinfinizin sahə/metoduna) “daxil ola” biləcəyini müəyyənləşdirir. Əgər bütün qapılar açıqdırsa — istənilən kəs gəlib nəsə dəyişə bilər. Əgər hər şey bağlıdırsa — heç kim heç nə poza bilməz, amma elə də ola bilər ki, bir anda siz özünüz kiliddə qalasınız.
Xatırladaq ki, Java-da dörd əsas giriş səviyyəsi var:
| Modifikator | Sinif daxilində əlçatandır | Paket daxilində əlçatandır | Alt siniflərdə əlçatandır | Digər paketlərdə əlçatandır |
|---|---|---|---|---|
|
✔ | |||
| (package) | ✔ | ✔ | ||
|
✔ | ✔ | ✔ | (mirasalma vasitəsilə) |
|
✔ | ✔ | ✔ | ✔ |
(package) — modifikator açıq şəkildə göstərilmədikdə. Belə sinif üzvü yalnız bir paket daxilində görünür.
2. Giriş modifikatorları ilə bağlı tipik səhvlər
Səhv 1: Susmaya görə modifikatorlu sahələr və metodlar (package-private)
Yeni başlayanların ən çox etdiyi səhv — giriş modifikatorunu göstərməyi unutmaqdır. Nəticədə sahə və ya metod bütün paketdə əlçatan olur, halbuki bunu planlaşdırmamışdınız. Bu o vaxta gətirib çıxara bilər ki, (eyni paketdə olan, amma sizinlə bağlı olmayan) başqa sinif obyektinizin daxili vəziyyətini dəyişə bilsin.
// Səhv: name sahəsi qorunmur!
class User {
String name; // package-private!
}
Nəticədə bu paketdəki istənilən sinif belə yaza bilər:
User user = new User();
user.name = "Vasya"; // məhdudiyyətsiz!
Səhv 2: İnkapsulyasiyanın pozulması — açıq sahələr (public)
İkinci ən yayğın səhv — sinif sahələrini public elan etməkdir. Bu, siz yeni öyrənəndə və ya qısa nümunə yazanda rahat görünə bilər, amma real layihələrdə bu demək olar ki, həmişə pisdir. Məlumatlarınızın kim və necə dəyişməsinə nəzarəti itirirsiniz.
public class Account {
public double balance; // Təhlükəli!
}
İndi istənilən kod aşağıdakı kimi edə bilər:
Account acc = new Account();
acc.balance = -1000000; // Bəs indi günahkar kimdir?
Səhv 3: Getter və setter-lərin olmaması
Bəzən tərtibatçı sahələri private edir, lakin onları idarə etmək üçün metodları əlavə etməyi unudur. Nəticədə dəyəri əldə etmək və ya dəyişmək mümkün olmur — halbuki bəzi hallarda bu uyğun olardı.
public class Product {
private String name;
// Nə getName(), nə də setName() var
}
Səhv 4: Başqa sinifdən private-üzvlərə müraciət cəhdi
Əgər sahəni və ya metodu private kimi elan etmisinizsə, ona başqa sinifdən müraciət etmək olmaz, hətta həmin sinif eyni paketdə olsa belə. Yeni başlayanlar tez-tez niyə sahənin “görünmədiyinə” təəccüblənirlər.
public class User {
private String password;
}
public class UserService {
public void resetPassword(User user) {
// user.password = "123"; // Kompilyasiya xətası!
}
}
Səhv 5: protected ilə bağlı səhvlər
Bir çoxları protected-in “harada mirasalma varsa, hər yerdə görünür” demək olduğunu hesab edir. Amma Java-da paketdən kənarda protected-üzvlərə giriş yalnız mirasalma vasitəsilə və yalnız alt sinif üçün mümkündür. Bu, asanlıqla gözdən qaçan bir incəlikdir.
package animals;
public class Animal {
protected void sleep() {}
}
package zoo;
import animals.Animal;
public class Dog extends Animal {
public void test() {
sleep(); // OK — varis
}
}
public class NotADog {
public void test() {
Animal a = new Animal();
// a.sleep(); // Xəta: varis deyil!
}
}
3. Necə düzgün: ən yaxşı təcrübələr
Qayda 1: Standart olaraq sahələri private edin
Bu, inkapsulyasiyanın əsas prinsipidir. Sahələr sinfin özündən başqa hamıdan gizli olmalıdır. Əgər giriş vermək lazımdırsa — getter/setter-lərdən istifadə edin.
public class Book {
private String title;
private int pages;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
Qayda 2: Yalnız zəruri metodları açın
Əgər metod kənardan əlçatan olmalıdırsa — onu public edin. Yalnız paket daxilində lazımdırsa — package-private saxlayın. Metod yalnız varislər üçün nəzərdə tutulubsa — protected istifadə edin.
Qayda 3: Görünürlük sahəsini minimuma endirin
Görünürlük sahəsi nə qədər kiçikdirsə, təsadüfi səhvlər və “gözlənilməz qonaqlar” ehtimalı da o qədər azdır. Zərurət olmadıqca metod və sahələri public etməyin.
Qayda 4: Girişə nəzarət üçün getter və setter-lərdən istifadə edin
Bu, sahəni oxuyarkən/yazarkən əlavə məntiq (məsələn, validasiya) əlavə etməyə imkan verir.
public class Account {
private double balance;
public void setBalance(double balance) {
if (balance < 0) {
throw new IllegalArgumentException("Balans mənfi ola bilməz!");
}
this.balance = balance;
}
public double getBalance() {
return balance;
}
}
Qayda 5: Daxili reallaşdırmanı açmayın
Əgər sahə kimi massiv və ya siyahı saxlayırsınızsa, onu getter vasitəsilə birbaşa qaytarmayın — nüsxə qaytarın və ya yalnız lazım olan metodları təqdim edin.
public class Team {
private List<String> members = new ArrayList<>();
// Düzgün:
public List<String> getMembers() {
return new ArrayList<>(members); // nüsxəni qaytarırıq
}
}
4. Praktik nümunələr
Tutaq ki, bizdə kitabxana istifadəçisini təsvir edən LibraryUser sinfi var.
Yanlış reallaşdırma nümunəsi
public class LibraryUser {
public String name;
public int borrowedBooks;
}
Bu halda istənilən kod obyektlə istədiyini edə bilər:
LibraryUser user = new LibraryUser();
user.name = null;
user.borrowedBooks = -10; // Məntiq? Hansı məntiq?
İnkapsulyasiyalı düzgün reallaşdırma nümunəsi
public class LibraryUser {
private String name;
private int borrowedBooks;
public LibraryUser(String name) {
this.name = name;
this.borrowedBooks = 0;
}
public String getName() {
return name;
}
public int getBorrowedBooks() {
return borrowedBooks;
}
public void borrowBook() {
borrowedBooks++;
}
public void returnBook() {
if (borrowedBooks > 0) {
borrowedBooks--;
}
}
}
Artıq kənar kod götürülən kitabların sayını və ya istifadəçinin adını birbaşa dəyişə bilməz. Hər şeyə nəzarət yalnız sinfin metodları vasitəsilə həyata keçirilir.
5. Reallaşdırmanın xüsusiyyətləri və nüansları
Bəzən elə gəlir ki, bir sahəni public etmək, çoxlu getter və setter yazmaqdan daha asandır. Amma bu, tələdir! Açıq sahə — mənzilə açıq qapı kimidir: bəli, rahatdır, amma o qədər də təhlükəsiz deyil.
Daha bir incəlik — hər sahə üçün getter və setter yazmağa həmişə ehtiyac yoxdur. Əgər sahənin dəyəri obyekt yaradıldıqdan sonra dəyişməməlidirsə, yalnız getter yazın, sahəni isə final edin:
public class Passport {
private final String number;
public Passport(String number) {
this.number = number;
}
public String getNumber() {
return number;
}
}
Həmçinin yadda saxlayın: əgər sinif public elan edilibsə, faylın adı sinfin adı ilə eyni olmalıdır! Bu, tam olaraq giriş modifikatorları barədə olmasa da, yeni başlayanların çox etdiyi bir səhvdir.
6. Giriş modifikatorları ilə işləyərkən tipik səhvlər
Səhv №1: sahə və ya metod üçün giriş modifikatorunu göstərməyi unutmusunuz. Nəticədə sahə və ya metod bütün paketdə əlçatan olur, halbuki bunu istəməmişdiniz. IDE xəbərdarlıq etməsə belə, modifikatoru həmişə açıq şəkildə göstərin.
Səhv №2: bütün sahələr public kimi elan edilib. Bu, inkapsulyasiyanı məhv edir, kodunuzu həssas və proqnozlaşdırılmaz edir. “Sadəlik üçün” nümunələrindən qalan vərdiş iş koduna düşməməlidir.
Səhv №3: başqa sinifdən private sahəyə müraciət cəhdi. Java buna icazə verməyəcək — kompilyator sizi qoruyacaq, amma əgər bunu “refleksiya vasitəsilə keçmək” istədinizsə — ümumiyyətlə niyə belə bir ehtiyacın yarandığını düşünün.
Səhv №4: protected üzvlərin mirasalma olan hər yerdə əlçatan olacağını gözləmək. Əslində, paketdən kənarda onlara yalnız alt sinifdən və yalnız this vasitəsilə və ya alt sinif obyektindən müraciət etmək olar.
Səhv №5: daxili kolleksiyanı getter vasitəsilə qaytarmaq. Əgər daxili massivə və ya siyahıya istinad qaytarsanız, kənar kod onu dəyişə bilər və bu da sinfin invariantlarını poza bilər.
Səhv №6: setter vasitəsilə dəyər təyin edilərkən nəzarətin olmaması. Gələn dəyəri yoxlamasanız, obyektin qeyri-korrekt vəziyyətini ala bilərsiniz (məsələn, mənfi balans).
Səhv №7: metodların həddindən artıq geniş görünürlüyü. Bəzən metodlar public edilir, baxmayaraq ki, onlar yalnız paket və ya sinif daxilində lazımdır. Bu, artıq API-ni açır və dəstəyi çətinləşdirir.
GO TO FULL VERSION