Kolejna porcja Javy! Dzisiaj sobie wyjaśnimy dlaczego pakiety tworzone za pomocą słowa "package" w języku Java są szeroko wykorzystywane. Może Wy jesteście zainteresowani powodami stosowania pakietów i zasad ich wykorzystywania w praktyce :)?
Tweet |
"PACKAGE" W JĘZYKU JAVA. DEFINICJA I POWODY TWORZENIA PAKIETÓW
Pakiet stanowi grupę czy też podzbiór utworzonych klas celem posegregowania ich według przeznaczenia. Działa to identycznie jak ma to miejsce w drzewie katalogów. Filmy pakujemy do filmów, obrazki do obrazków, a skróty jak nie mieszczą się na pulpicie, to też powinniśmy znaleźć dla nich folder :). W Javie wcale nie jest inaczej, aczkolwiek trzeba wiedzieć że to NIE JEST jedyny powód ich stosowania :D.
Jeżeli zajrzymy do dokumentacji, to zauważymy, że wszystko ma swoje miejsce i swój własny pakiet. A ten pakiet może mieć własne inne pakiety i dopiero te "podpakiety" mogą dysponować klasami. Słynna kolekcja "ArrayList" na przykład pochodzi z pakietu "util" (skrót od "utilities"), a ten pakiet z kolei należy do rodziny wszystkich pakietów, "java". W ten sposób mamy ten sam ciąg, który widzimy wielokrotnie podczas importowania, "java. util.ArrayList". Gdy korzystaliśmy z "BufferedReader", to też musieliśmy zaimportować stosowny pakiet (nie bibliotekę!). Zatem sięgaliśmy do "java", "io" i tam mieliśmy "BufferedReader".
Słowo kluczowe "package" w języku Java jest wykorzystywane jeszcze z jednego powodu: minimalizuje szansę na wystąpienie kolizji nazw! Jest pewne na 99%, że pracując w zespole ktoś wymyśli taką samą nazwę jak Wy. Zatem trzeba nasz pakiet osadzić w większy pakiet, który będzie miał bardziej unikatową nazwę.
PRZYJĘTA KONWENCJA NAZEWNICZA DLA PAKIETÓW
Tak się składa, że wprowadzono obowiązującą konwencję nazewniczą. Przyjęło się, że pakiety tworzone przy użyciu "package" w języku Java powinny mieć strukturę nazewniczą w postaci odwróconej nazwy naszej domeny. Tak więc podstawiając pod mój przypadek, należałoby zapisać to tak:
package pl.jasonxiii.[nazwa klasy];
Dzięki temu, jest możliwość zminimalizowania występowania kolizji nazw w przypadku, gdyby ktoś inny na przykład zaimportował mój pakiet i też zbudowałby klasę o tej samej nazwie. Mimo tego, że klasy nosiłyby tę samą nazwę, to wyróżniałyby je nazwy pakietów i w ten sposób problem znika :).
PEŁNA NAZWA KLASY W PAKIECIE I WPŁYW IMPORTU
Pamiętajcie, że w sytuacji, kiedy dana klasa należy do pakietu, to w rzeczywistości otrzymuje pełną nazwę o postaci przedstawionej u góry. Dlatego też w przypadku próby skorzystania z tej samej nazwy klasy pochodzącej z dwóch różnych pakietów, trzeba wobec jednej z nich wprowadzić pełną nazwę tj. cały ciąg pakietów! To pokazuje, że import pakietu ma za zadanie jedynie skrócić ciąg do samej nazwy klasy:
import pl.jasonxiii.exampleA.Example;
public class Main {
public static void main(String[] args) {
Example exampleA = new Example();
pl.jasonxiii.exampleB.Example exampleB = new pl.jasonxiii.exampleB.Example();
}
}
Na tym kodzie źródłowym widzimy już doskonale jak wygląda ciąg "pełny" i "skrócony" przez import pakietu.
KOMPILOWANIE KODU Z PAKIETÓW
Kompilując to wszystko ręcznie przy użyciu jedynie wiersza poleceń, na pewno niejeden z Was zastanawiał się czemu znowu coś nie działa. Dzisiaj nikogo nie będzie dziwić korzystanie z dowolnego IDE, aczkolwiek warto chociaż parę razy w życiu skompilować swój kod manualnie od początku do końca, aby się dowiedzieć jak to działa w rzeczywistości. Pakiety w języku Java mocno komplikują proces ręcznej kompilacji i tym się teraz zajmiemy, zanim zakończę temat.
Tym razem zapodam jedną jedyną klasę, która przyda się do eksperymentu. Zróbcie sobie nowy katalog, a w nim utwórzcie "ciąg" podfolderów, które MUSZĄ odpowiadać ciągowi podanemu po słowie kluczowym "package" w języku Java. Czyli w folderze głównym tworzycie folder o nazwie "X", a w nim tworzycie kolejny folder "Y" (możecie po nim dać jeszcze więcej). Właśnie tam zapiszcie plik z rozszerzeniem ".java" wklejając poniższą zawartość:
package [X].[Y];
public class Main {
public static void main(String[] args) {
System.out.println("Program działa!");
}
}
Pakiety w języku Java są niczym innym jak ciągiem podfolderów, które przypominają strukturę drzewa. Po każdej kropce "schodzi się" poziom niżej i w ten sposób można dostać się w każde miejsce zaczynając od "korzenia", jakim jest nasz folder główny. Po zapisaniu pliku z rozszerzeniem ".java", otwórzcie sobie wiersz poleceń (najlepiej z uprawnieniami administratora) i przy pomocy polecenia "cd", przejdźcie bezpośrednio do katalogu posiadającego folder o nazwie "X". Wpisując poniższe polecenie:
javac [X]/[Y]/[nazwa pliku źródłowego].java
kompilator Javy przejdzie wówczas po wszystkich katalogach jeden po drugim i skompiluje program, o ile ciąg po słowie "package" w języku Java zgadza się ze wszystkimi podfolderami. Pakiety są wyjątkowo czułe na literówki, więc w przypadku wystąpienia błędu, upewnijcie się że wpisaliście wszystkie nazwy perfekcyjnie. Znaki diakrytyczne najlepiej obejść szerokim łukiem. Jeżeli poprzednie polecenie niczego nie wypisuje, to znak że kompilacja się udała. W celu uruchomienia skompilowanego programu, zostajemy w tym samym folderze i wpisujemy to:
java [X].[Y].Main
Zwróćcie uwagę, że teraz są kropki zamiast slash'y, tak jak się wpisało w kodzie po słowie kluczowym "package"! Też wyjątkowo łatwo się pomylić, więc pozostaje Wam tylko "wejście w krew". Jeżeli kompilacja, to znaki ukośników. Jeżeli uruchamianie, to kropki. Przyjrzyjcie się poniższemu obrazkowi i zobaczcie jakie są różnice:
Pakiety tworzą "drzewiastą" strukturę katalogów, która umożliwia segregację plików źródłowych i klasowych.
Stosowanie pakietów i ich właściwe rozumienie jest KLUCZOWE przy wykorzystywaniu archiwum JAR oraz tzw. "manifestu".
To było wyjaśnienie i teoretyczne, i praktyczne. Słowo kluczowe "package" w języku Java powinno być wykorzystywane W KAŻDYM Waszym programie i należy to robić z głową, nieważne czy z pomocą IDE, czy nie.