1. Paketlərin eksportu: kodunuzu kim görür?
Java 9-dan əvvəl hər şey sadə idi. Amma o qədər də təhlükəsiz deyildi. Əgər sinif public idisə, JAR-a və ya classpath-ə çıxış olduqda onu istənilən kəs görə bilirdi. Nəticədə daxili siniflər və hətta bütöv paketlər layihənizin xaricində təsadüfən və ya qəsdən istifadə oluna bilərdi. Bəli, nələri isə private və ya package-private ilə gizlətmək olardı, amma sinif publicdirsə — o, hər kəsə əlçatandır.
Modulların gəlişi ilə bu dəyişdi. İndi hətta sinif public elan olunsa belə, o, yerləşdiyi paket module-info.java-da exports vasitəsilə açıq şəkildə eksport edilməyibsə, başqa moduldən istifadə oluna bilməz.
Bu praktikada necə görünür
Tutaq ki, layihə strukturu belədir:
my-app/
src/
core/
com/example/core/
CoreService.java
InternalHelper.java
module-info.java
app/
com/example/app/
Main.java
module-info.java
core/module-info.java faylında yazırsınız:
module core {
exports com.example.core;
}
O zaman yalnız com.example.core paketindəki siniflər digər modullara əlçatan olacaq. Digər paketlərdə olan hər şey (məsələn, com.example.core.internal) görünməyəcək — hətta orada public siniflər olsa belə. Bu, modul inkapsulyasiyasıdır.
Mini-demo: «görünür/görünmür»
core daxilində:
// com/example/core/CoreService.java
package com.example.core;
public class CoreService {
public void doWork() {
System.out.println("Work done!");
}
}
app daxilində:
// com/example/app/Main.java
package com.example.app;
import com.example.core.CoreService;
public class Main {
public static void main(String[] args) {
CoreService service = new CoreService();
service.doWork();
}
}
Əgər core/module-info.java faylından exports com.example.core; sətrini silsəniz, kompilyasiya zamanı bu xətanı alacaqsınız:
error: package com.example.core is not visible
Hətta CoreService — public olsa belə!
2. Asılılıqların importu: requires və sərt izolasiya
JPMS-də başqa moduldan sinifi sadəcə götürüb istifadə etmək olmur. Asılılığı açıq şəkildə requires vasitəsilə elan etmək lazımdır.
Nümunə
app/module-info.java faylında:
module app {
requires core;
}
İndi app modulu, core modulunun eksport etdiyi hər şeyi istifadə edə bilər.
Əgər requires core; yazmağı unutdunuzsa, kompilyasiya xətası alacaqsınız:
error: package com.example.core is not visible
və ya
error: cannot access CoreService
Vacib məqam
- requires paketlər yox, modul səviyyəsində işləyir.
- Yalnız bir paketi “import” edə bilməzsiniz — yalnız bütün eksport olunan modulu.
3. Müqayisə: modullar və public/private
Modullar siniflər və paketlərin “üzərində” yerləşən yeni inkapsulyasiya səviyyəsi əlavə edir.
| Səviyyə | Nəyi tənzimləyir? | Necə işləyir? |
|---|---|---|
| private | Giriş sinif daxilində | Yalnız bir fayl daxilində |
| package-private (susmaya görə) | Paket daxilində giriş | Eyni paketdəki bütün siniflər |
| public | Hamı üçün giriş | İstənilən yerdə istənilən kod |
| module | Modullar arasında giriş | Yalnız eksport olunan paketlər |
Açar fikir:
- Sinif public ola bilər, amma onun paketi eksport olunmayıbsa, o yalnız modul daxilində əlçatan olacaq.
- exports vasitəsilə paketin eksportu — digər modulların kodunuzu gördüyü bir “pəncərə” kimidir.
Nümunə: gizlədilmiş reallaşdırma
// com/example/core/internal/SecretSauce.java
package com.example.core.internal;
public class SecretSauce {
public void addMagic() {}
}
Əgər module-info.java-da com.example.core.internal paketini EKSPORT ETMƏSƏNİZ, heç bir xarici modul bu sinifdən istifadə edə bilməz, hətta o public olsa belə!
4. Nümunə: core və app — API və reallaşdırma
Tipik ssenarini nəzərdən keçirək: core modulu API təqdim edir, app modulu — ondan istifadə edir.
Struktur:
core/
com/example/core/
CoreAPI.java
com/example/core/impl/
CoreImpl.java
module-info.java
app/
com/example/app/
Main.java
module-info.java
core/module-info.java:
module core {
exports com.example.core; // Yalnız API!
// com.example.core.impl-i eksport etmirik
}
app/module-info.java:
module app {
requires core;
}
com/example/core/CoreAPI.java:
package com.example.core;
public interface CoreAPI {
void doSomething();
}
com/example/core/impl/CoreImpl.java:
package com.example.core.impl;
import com.example.core.CoreAPI;
public class CoreImpl implements CoreAPI {
@Override
public void doSomething() {
System.out.println("Doing something!");
}
}
com/example/app/Main.java:
package com.example.app;
import com.example.core.CoreAPI;
// import com.example.core.impl.CoreImpl; // Bu, kompilyasiya xətasına səbəb olacaq!
public class Main {
public static void main(String[] args) {
// CoreImpl impl = new CoreImpl(); // Xəta! Paket eksport edilmir.
// Yalnız API vasitəsilə görünənləri istifadə etmək olar.
}
}
Nəticə:
- app modulu yalnız core modulunun eksport etdiklərini görür.
- Reallaşdırma (impl) gizlədilib, hətta oradakı siniflər public olsa belə.
5. Praktika: export və görünürlük ilə oynayırıq
Addım 1: export-u silirik
core/module-info.java faylında sətri şərhə alın:
// exports com.example.core;
İndi layihəni kompilyasiya etməyə çalışın. app modulunda kompilyasiya xətası gözləyin — o, com.example.core paketindəki sinifləri görməyəcək.
Addım 2: yalnız API-ni eksport edirik
exports com.example.core; sətrini geri qaytarın, amma com.example.core.impl-i eksport etməyin. app modulunda impl paketindən sinif import etməyə çalışın. Yenə kompilyasiya xətası alacaqsınız — hər şey qaydasındadır!
Addım 3: eksport edilməyən paketdə public sinif
Eksport edilməyən paketdə public sinif yaradın. Ondan başqa moduldan istifadə etməyə çalışın — alınmayacaq. Bu, modul inkapsulyasiyasının iş başında olan halıdır.
6. Bu, IDE-də və «sadə dildə» necə görünür
- Eksport edilməyən paketdən sinif import etməyə cəhd edərkən IDE xəta ilə vurğulayacaq.
- İpucu paketin modul tərəfindən eksport edilmədiyini izah edəcək.
- Lazım olan paket üçün exports əlavə edin — xəta yox olacaq.
Sxem: giriş səviyyələri
+---------------------+
| MODUL |
| (module-info.java) |
+---------------------+
|
v
+---------------------+
| PAKETLƏR |
| (package, export) |
+---------------------+
|
v
+---------------------+
| SİNİFLƏR |
| (public/private) |
+---------------------+
|
v
+---------------------+
| METODLAR/SAHƏLƏR |
| (public/private) |
+---------------------+
7. Vacib nüanslar və xüsusiyyətlər
«Yalnız dostlar» üçün eksport: exports ... to
Bəzən paketi yalnız müəyyən modullar üçün eksport etmək lazımdır (məsələn, testlər və ya xüsusi genişlənmələr üçün):
exports com.example.core.internal to my.special.module, my.test.module;
Artıq yalnız göstərilən modullar bu paketi görəcək.
Bir neçə paketi eksport etmək olarmı?
Bəli! Sadəcə yeni exports sətrləri əlavə edin:
exports com.example.core;
exports com.example.core.api;
“Hər şeyi” eksport etmək olarmı?
Xeyr. Java-nın modul sistemində siz həmişə nələri eksport edəcəyinizi açıq göstərirsiniz. Məhz bu, onun gücüdür.
8. Modul inkapsulyasiyası ilə işləyərkən tipik səhvlər
Səhv №1: public sinifin həmişə görünəcəyini düşünmək.
Əgər paket module-info.java vasitəsilə eksport edilməyibsə, sinif digər modullar üçün görünməyəcək, hətta o public olsa belə. Bu, yeni başlayanlar üçün ən çox rast gəlinən “tələ”dir.
Səhv №2: requires elanını unutmaq.
Modulunuz başqa modulun siniflərindən istifadə edir, amma requires yazılmayıbsa, kompilyasiya xətası alacaqsınız. Asılılıqları açıq şəkildə təsvir etməyi unutmayın.
Səhv №3: eyni paketi iki moduldan eksport etməyə cəhd.
JPMS-də hər paket yalnız bir modul tərəfindən eksport edilə bilər. Bu qaydanı pozsanız, kompilyator sizi dayandıracaq.
Səhv №4: strukturun pozulması — module-info.java düzgün yerdə deyil.
module-info.java faylı modulun mənbələrinin kökündə yerləşməlidir, əks halda modul tanınmayacaq.
Səhv №5: modullar arasında dövri asılılıqlar.
Əgər A modulu B-ni tələb edir, B isə A-nı tələb edirsə — xəta alacaqsınız. Asılılıqlar qrafında dövrlərdən qaçın.
GO TO FULL VERSION