U ovoj sekciji ćemo ukratko proći kroz pakete u Javi, odnosno package — to se brzo shvata i lako svlada.
„Erge, sačekaj trenutak“, rekla je. „Da otvorim mentalnu mapu i zapisujem beleške.“
O paketima
U prethodnom kodu klase i interfejse smo imenovali jednostavnim imenima kao što su Person, Student, Hello.
U timskom razvoju, ako Xiao Ming napiše klasu Person i Xiao Hong takođe napiše klasu Person, šta Xiao Bai da radi kad želi da koristi i Xiao Mingovu i Xiao Hongovu klasu Person?
Ako Xiao Jun napiše klasu Arrays, a JDK slučajno već dolazi sa ugrađenom klasom Arrays, kako rešiti sukob imena?
U Javi sukob imena rešavamo upotrebom package.
Java definiše jedan prostor imena koji se naziva paket: package. Klasa uvek pripada nekom paketu — ime klase (npr. Person) samo je skraćeni zapis, dok je pravo puno ime klase oblika imePaketa.ImeKlase.
Na primer:
Klasa Person Xiao Minga nalazi se u paketu ming, pa je puno ime klase ming.Person;
Klasa Person Xiao Hong nalazi se u paketu hong, pa je puno ime klase hong.Person;
Klasa Arrays Xiao Juna nalazi se u paketu mr.jun, pa je puno ime klase mr.jun.Arrays;
Klasa Arrays iz JDK-a nalazi se u paketu java.util, pa je puno ime klase java.util.Arrays.
Pri definisanju class, u prvom redu treba navesti kojem paketu taj class pripada.
Xiao Mingov fajl Person.java:
package ming; // navođenje imena paketa ming
public class Person {
}Xiao Junov fajl Arrays.java:
package mr.jun; // navođenje imena paketa mr.jun
public class Arrays {
}Kada Java virtuelna mašina izvršava kod, JVM gleda isključivo puno ime klase, tako da — dokle god se imena paketa razlikuju, i klase su različite.
Paket može biti višeslojne strukture, razdvojen sa .. Na primer: java.util.
Važno: paketi nemaju odnos roditelj-dete. java.util i java.util.zip su različiti paketi i između njih ne postoji nikakav odnos nasleđivanja.
Klasa class bez definisanog imena paketa koristi podrazumevani paket, što veoma lako izaziva sukob imena, pa se ne preporučuje praksa da se ime paketa izostavi.
Takođe moramo prema strukturi paketa da organizujemo gorenavedene Java fajlove. Ako je package_sample koreni direktorijum, a src direktorijum za izvorni kod, onda je struktura svih fajlova sledeća:
package_sample
└─ src
├─ hong
│ └─ Person.java
│ ming
│ └─ Person.java
└─ mr
└─ jun
└─ Arrays.javaTo jest, direktorijumska hijerarhija svih Java fajlova mora se poklapati sa hijerarhijom paketa.
Kompajlirani .class fajlovi takođe moraju biti smešteni prema strukturi paketa. Ako koristite IDE i kompajlirane .class fajlove stavite u direktorijum bin, onda je struktura kompajliranih fajlova sledeća:
package_sample
└─ bin
├─ hong
│ └─ Person.class
│ ming
│ └─ Person.class
└─ mr
└─ jun
└─ Arrays.classKomanda za kompiliranje je relativno složena — u direktorijumu src moramo izvršiti komandu javac:
javac -d ../bin ming/Person.java hong/Person.java mr/jun/Arrays.javaU IDE-u se automatski vrši kompilacija svih Java izvornih fajlova na osnovu strukture paketa, tako da ne morate da brinete o složenim komandama iz komandne linije.
Opseg važenja paketa
Klase koje se nalaze u istom paketu mogu da pristupaju poljima i metodama u opsegu paketa.
Polja i metode koji nisu modifikovani sa public, protected ili private nalaze se u opsegu paketa. Na primer, klasa Person definisana je u paketu hello:
package hello;
public class Person {
// opseg paketa:
void hello() {
System.out.println("Hello!");
}
}Klasa Main, koja je takođe definisana u paketu hello, može neposredno da pristupi klasi Person:
package hello;
public class Main {
public static void main(String[] args) {
Person p = new Person();
p.hello(); // može se pozvati, jer su Main i Person u istom paketu
}
}Uvoz paketa
Unutar jednog class uvek referenciramo druge class. Na primer, Xiao Mingova klasa ming.Person, ukoliko želi da referencira Xiao Junovu klasu mr.jun.Arrays, ima tri načina zapisa.
Prvi način je da se neposredno napiše puno ime klase, na primer:
// Person.java
package ming;
public class Person {
public void run() {
mr.jun.Arrays arrays = new mr.jun.Arrays();
}
}Očigledno je prilično naporno svaki put pisati puno ime klase.
Zato je drugi način zapisa upotreba naredbe import koja uvozi Xiao Junovu klasu Arrays, a zatim korišćenje skraćenog imena klase:
// Person.java
package ming;
// uvozi se puno ime klase:
import mr.jun.Arrays;
public class Person {
public void run() {
Arrays arrays = new Arrays();
}
}Pri pisanju import može se koristiti *, čime se uvoze sve class iz tog paketa (ali ne i class iz podpaketa):
// Person.java
package ming;
// uvozi se sav class iz paketa mr.jun:
import mr.jun.*;
public class Person {
public void run() {
Arrays arrays = new Arrays();
}
}Ovakav način pisanja se uglavnom ne preporučuje, jer nakon uvoza više paketa postaje teško ustanoviti kom paketu klasa Arrays pripada.
Postoji i sintaksa import static, koja može uvesti statička polja i statičke metode jedne klase:
package main;
// uvoze se sva statička polja i statičke metode klase System:
import static java.lang.System.*;
public class Main {
public static void main(String[] args) {
// ekvivalentno pozivu System.out.println(…)
out.println("Hello, world!");
}
}import static se retko koristi.
Java kompajler u konačnom .class fajlu koristi isključivo puno ime klase, tako da kada kompajler u kodu naiđe na ime nekog class:
- Ako je u pitanju puno ime klase, taj
classse traži neposredno preko punog imena; - Ako je u pitanju skraćeno ime klase, pretraživanje se obavlja sledećim redosledom:
- proverava se da li taj
classpostoji u trenutnompackage; - proverava se da li taj
classpostoji uimport-ovanim paketima; - proverava se da li taj
classpostoji u paketujava.lang.
- proverava se da li taj
Ako se prema gorenavedenim pravilima i dalje ne može utvrditi ime klase, kompajler prijavljuje grešku.
Pogledajmo primer:
// Main.java
package test;
import java.text.Format;
public class Main {
public static void main(String[] args) {
java.util.List list; // u redu, koristi se puno ime klase -> java.util.List
Format format = null; // u redu, koristi se import-ovana klasa -> java.text.Format
String s = "hi"; // u redu, koristi se String iz paketa java.lang -> java.lang.String
System.out.println(s); // u redu, koristi se System iz paketa java.lang -> java.lang.System
MessageFormat mf = null; // greška pri kompiliranju: ne može se pronaći MessageFormat: MessageFormat cannot be resolved to a type
}
}Prema tome, prilikom pisanja klase kompajler automatski obavlja dve import akcije:
- podrazumevano automatski
import-uje sve ostaleclassiz trenutnogpackage; - podrazumevano automatski
import-ujejava.lang.*.
Napomena: automatski se uvozi paket java.lang, ali pakete poput java.lang.reflect i dalje treba ručno uvesti.
Ako dva class imaju isto ime, na primer mr.jun.Arrays i java.util.Arrays, onda se može import-ovati samo jedan od njih, dok drugi mora biti napisan punim imenom klase.
Najbolje prakse za pakete
Da bismo izbegli sukob imena, moramo obezbediti jedinstveno ime paketa. Preporučena praksa je korišćenje obrnutog imena domena radi osiguranja jedinstvenosti. Na primer:
- org.apache
- org.apache.commons.log
- com.tobebetterjavaer.sample
Podpaketi se mogu imenovati prema funkciji.
Treba voditi računa da ime vaše klase ne bude isto kao ime klase iz paketa java.lang, odnosno da vaše klase ne koriste sledeća imena:
- String
- System
- Runtime
- ...
Treba voditi računa i da ime ne bude isto kao kod često korišćenih JDK klasa:
- java.util.List
- java.text.Format
- java.math.BigInteger
- ...
Rezime
Ugrađeni mehanizam package u Javi služi da se izbegne sukob pri imenovanju class;
Ključne klase JDK-a koriste paket java.lang koji kompajler automatski uvozi;
Ostale često korišćene klase JDK-a definisane su u java.util.*, java.math.*, java.text.*, …;
Preporučuje se da ime paketa bude obrnuto ime domena, na primer org.apache.
Referentni link: https://www.liaoxuefeng.com/wiki/1252599548343744/1260467032946976, obradio: Chenmo Wang Er
