Pakiety klas
Pakiet to grupa powiązanych klas (typów) z określnymi modyfikatorami dostępu. Użycie pakietów zapewnia możliwość zarządzania określonymi przestrzeniami nazw - każdy pakiet stanowi odrębną przestrzeń nazw.
Klasy dostępne na platformie Java są pogrupowane w pakiety. Np. klasy podstawowe znajdują się w pakiecie java.lang, klasy odpowiedzialne za operacje we/wy znajdują się w pakiecie java.io.
Dla wygody, kompilator Javy zawsze domyślnie, automatycznie importuje dla każdego pliku źródłowego następujące dwa całe pakiety klas:
- pakiet java.lang, w którym znajdują się najczęściej używane klasy;
- bieżący pakiet (pakiet bieżącego pliku - aktualnie kompilowanego pliku) - czyli importowane są wszystkie klasy z katalogu, w którym znajduje się aktualnie kompilowany plik.
- ponadto importowane są wszystkie pakiety, które wystąpią w instrukcjach "import nazwa.pakietu..." napotkanych w kompilowanych plikach.
Dlaczego warto używać umieszczać klasy w pakietach...
- aby ułatwić wyszukiwanie i używanie klas przez odpowiednie grupowanie klas pokrewnych;
- aby uniknąć konfliktu nazw klas z odrębnych pakietów, gdy w różnych pakietach wystąpią klasy o takiej samej nazwie; łatwo wyobrazić sobie sytuację, w której będziesz chciał użyć klasy o nazwie Rectangle; jednakże istnieje już klasa Javy o takiej nazwie w pakiecie java.awt; dzięki mechanizmowi pakietów możesz utworzyć własną klasę Rectangle, która będzie odróżniana od klasy java.awt.Rectangle;
- aby zapewnić kontrolę dostępu do poszczególnych klas, pozwalając np. na nieograniczony wzajemny dostęp klasom z jednego pakietu, lecz ograniczając dostęp dla klas spoza pakietu.
Użycie klas bez określania pakietów ma uzasadnienie wyłącznie w wypadku bardzo małych lub tymczasowych programów. W każdej innej sytuacji warto i należy używać pakietów o określonych nazwach.
Konwencja dotycząca nazw pakietów
Aby utworzyć pakiet, koniecznie musisz określić nazwę pakietu.
Obowiązują następujące zasady dotyczące nazw pakietów:
- nazwy pakietów zaczynają się od małej litery, aby nie wystąpił konflikt z nazwami klas lub interfejsów,
- zgodnie z ogólnymi zasadami nazw Java nazwa pakietu nie może zaczynać się od cyfry; jeśli chcesz rozpocząć nazwę swojego pakietu od cyfry, poprzedź ją znakiem podkreślenia (underscore) - np. _123nazwapakietu.;
- nazwa pakietu nie może być żadnym zarezerwowanym słowem kluczowym Javy - np. użycie pakietu o nazwie int. jest niedozwolone; możesz jednak użyć nazwy _int. lub int_.;
- nazwy pakietów zarezerwowane dla klas języka Java to java. oraz javax.;
- zwyczajowo firma o adresie internetowym nazwafirmy.com zaczyna nazwy swoich pakietów oprogramowania od com.nazwafirmy., a dalej dodaje nazwy wewnętrznych-firmowych pakietów, aby uniknąć konfliktu nazw w firmowym oprogramowaniu;
- w nazwach pakietów nie mogą występować żadne znaki specjalne ani interpunkcyjne; zamiast myślnika użyj znaku podkreślenia - czyli np. w wypadku domeny nazwa-firmy.com użyj nazwy pakietu com.nazwa_firmy..
Gdy już określisz nazwę swojego pakietu zgodnie z opisaną wyżej konwencją, wykonaj następujące kroki:
1. w swoim katalogu roboczym utwórz podkatalog o nazwie twoja.nazwa.pakietu,
2. utwórz lub umieść w tym katalogu plik zawierający kod definicji twojej klasy,
3. na samym początku pliku zawierającego kod definicji twojej klasy wpisz widoczny niżej pierwszy wiersz:
package twoja.nazwa.pakietu;
class TwojaKlasa {
...
}
Korzystanie z klas należących do pakietów
Kompilator Javy widzi tylko bieżący folder, jego podfoldery oraz wszystkie foldery zapisane w zmiennej środowiskowej CLASS_PATH. Aby w bieżącym katalogu, w którym uruchamiasz narzędzie javac, był dostępny określony pakiet, pakiet ten musi występować w formie podkatalogu w katalogu bieżącym lub w dowolnym katalogu wskazanym w zmiennej środowiskowej CLASS_PATH.
Aby w klasie/obiekcie spoza pakietu użyć klasy należącej do określonego pakietu, należy wykonać jedną z trzech czynności:
- uzyskać dostęp do klasy przy użyciu w pełni kwalifikowanej nazwy składającej się
z nazwy pakietu oraz nazwy klasy,
PRZYKŁAD deklaracji zmiennej klasy Color z pakietu java.awt i zainicjowania tej zmiennej przy użyciu konstruktora klasy java.awt.Color:
java.awt.Color color = new java.awt.Color( 0, 0, 0 ); - zaimportować klasę z pakietu:
import java.awt.Color; class MojaKlasa{ Color color = new Color( 0, 0, 0 ); // Klasa Color z pakietu java.awt. jest dostępna, ponieważ została zaimportowana ... } - zaimportować cały pakiet:
import java.awt.*; class MojaKlasa{ Color color = new Color( 0, 0, 0 ); // Klasa Color z pakietu java.awt jest dostępna, ponieważ został zaimportowany cały pakiet ... }
Importowanie klas zagnieżdzonych
Aby zaimportować wszystkie klasy zagnieżdżone/wewnętrzne zdefiniowane wewnątrz np. klasy Outer, użyj następującej instrukcji:
import nazwa.pakietu.Outer.*;
Taka instrukcja nie zaimportuje klasy Outer, lecz wszystkie jej klasy wewnętrzne/zagnieżdżone. Aby zaimportować także klasę Outer, należy użyć następujących dwóch instrukcji:
import nazwa.pakietu.Outer;
import nazwa.pakietu.Outer.*;
Hierarchia pakietów
Jeśli na przykład wewnątrz pakietu java.awt. znajdją się pakiety podrzędne np.
java.awt.color, java.awt.font, pakiety te nie są
importowane po użyciu instrukcji
import java.awt.*;
Aby zaimportować pakiety java.awt.color i
java.awt.font, należy użyć dla każdego z nich osobnej instrukcji.
Np.:
import java.awt.*;
import java.awt.color.*;
import java.awt.font.*;
Dwuznaczność nazw
Jeśli zaimportujesz dwa pakiety, w których występują dwie lub więcej klas o takiej samej nazwie, wówczas należy w wypadku obu klas użyć w pełni kwalifikowanych nazw składających się z nazwy pakietu oraz nazwy klasy. Załóżmy, że utworzyłeś pakiet my.package, a w nim klasę Rectagle, zaimportowałeś go, a także zaimportowałeś pakiet java.awt, w którym również występuje klasa o nazwie Rectangle. W takiej sytuacji za każdym razem, gdy używasz klasy Rectangle, musisz określić, której klasy chcesz użyć w danym miejscu, podając pełną nazwę pakietu - w następujący sposób:
import my.package.*;
import java.awt.*;
class MyClass {
my.package.Rectangle myRectange = new my.package.Rectangle();
java.awt.Rectangle awtRectangle = new java.awt.Rectangle();
}
Importowanie metod statycznych
Istnieje możliwość zaimportowania wszystkich metod statycznych danej klasy, aby nie było konieczne wywoływanie tych metod przy użyciu nazwy klasy. Świetnym przykładem jest klasa Math z pakietu java.lang. Standardowo kompilator Javy automatycznie importuje pakiet java.lang. Dlatego nie musisz go importować jawnie w swoich programach. Jednakże aby wywołać funkcje matematyczne, musisz za każdym razem przed nazwą funkcji dodać nazwę klasy Math w następujący sposób:
double wynik = Math.sqrt( 9 );
Możesz też jawnie zaimportować wszystkie statyczne metody klasy Math i wówczas będziesz mógł wywołać funkcje matematyczne w następujący sposób:
import static java.lang.Math.*;
...
double wynik = sqrt( 9 );
Poprawi to przejrzystość kodu i ułatwi pisanie programu.
Kompilacja kodu korzystającego z pakietów
Jeśli struktura katalogów pakietów jest umieszczona w bieżącym katalogu, w którym znajduje się kompilowany plik zawierający dyrektywę importu pakietu/pakietów, wówczas kompilator automatycznie wyszuka pliki importowanych pakietów. Jeśli natomiast katalogi z pakietami znajdują się w innym miejscu, wówczas używając narzędzia javac należy zastosować parametr -cp z nazwą katalogu, w którym znajdują się odpowiednie pliki .class lub odpowiadające im pliki .java. Nazwa katalogu może być określona bezwzględnie lub względem katalogu bieżącego.
Ponadto warto oddzielić strukturę katalogów z plikami źródłowymi .java od katalogów z wynikowymi plikami kompilacji - plikami .class. Wówczas możliwe będzie udostępnienie twioch programów w formie kodu bajtowego bez udostępniania plików źródłowych z kodem w języku Java. Aby to zrobić, użyj narzędzia javac z opcją -d i nazwą katalogu, w którym mają znaleźć się wygenerowane pliki .class.