Eğitim Portalı/Java/Paketler (Packages)
Java01-java/35-paketler

Paketler (Packages)

Bir proje büyüdükçe yüzlerce, binlerce sınıf olur. Bunları tek bir klasöre yığmak hem kaosa yol açar hem de isim çakışmalarına (iki farklı Date sınıfı gibi) neden olur. Paketler, sınıfları mantıksal gruplara ayıran ve…

Paketler (Packages)

Bir proje büyüdükçe yüzlerce, binlerce sınıf olur. Bunları tek bir klasöre yığmak hem kaosa yol açar hem de isim çakışmalarına (iki farklı Date sınıfı gibi) neden olur. Paketler, sınıfları mantıksal gruplara ayıran ve her birine benzersiz bir isim alanı (namespace) veren mekanizmadır. Java'nın kendi kütüphanesi de paketlerle düzenlenmiştir: java.util, java.io, java.net...

Paket nedir?

Paket, ilişkili sınıfları bir araya getiren isimlendirilmiş bir gruptur. Bir sınıfın paketini, dosyanın başındaki package bildirimi belirler ve bu, klasör yapısıyla eşleşir:

package com.egitim.uygulama.servis;  // dosya: com/egitim/uygulama/servis/SiparisServisi.java
public class SiparisServisi { ... }

Bir sınıfın tam nitelikli adı (fully-qualified name, FQN) = paket + sınıf adı: com.egitim.uygulama.servis.SiparisServisi.

İsimlendirme geleneği: Paket adları, çakışmayı önlemek için kurumun ters domain'iyle başlar: com.sirket.proje.modul. Hepsi küçük harftir.

Not: Bu portalın örnekleri tek dosyada (default pakette) çalışır; bu yüzden kendi paketlerimizi oluşturmak yerine, JDK'nin paketlerini (java.util, java.math...) kullanarak import ve FQN kavramlarını gösteriyoruz.

import: kısa adla kullanım

Başka bir paketteki sınıfı kullanmak için ya tam adını yazarsın ya da import ile kısa adını getirirsin:

import java.util.List;          // tek sınıf
import java.util.*;             // paketteki tüm sınıflar (yıldız)
List<String> liste = ...;       // artık kısa adla

java.lang paketi (String, System, Math, Integer...) otomatik içe aktarılır; onları import etmen gerekmez. Örnek 1 (./Ornek1.java) import'u, tam nitelikli adı ve bir isim çakışmasının (java.util.Date vs java.sql.Date) FQN ile nasıl çözüldüğünü gösterir.

static import

Normal import bir sınıfı getirir; static import ise bir sınıfın statik üyelerini (alan/metot) doğrudan kullanmanı sağlar:

import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
double alan = PI * sqrt(r);   // Math.PI / Math.sqrt yerine

Matematik ağırlıklı kod ve testlerde (assertEquals) okunabilirliği artırır. Örnek 2 (./Ornek2.java) Math ve Collectors'tan static import gösterir. Aşırı kullanım "bu metot nereden geliyor?" karışıklığı yarattığından ölçülü kullanılmalıdır.

Paket-özel erişim ve düzen

Erişim belirleyiciler bölümünde gördüğümüz default (paket-özel) erişim, paketlerle birlikte anlam kazanır: belirleyici yazılmayan üyeler yalnızca aynı paketten erişilir. Bu, bir paketin "iç" sınıflarını dışarıya kapatmak için kullanılır.

package-info.java adlı özel bir dosya ile bir pakete dokümantasyon ve paket düzeyi anotasyonlar eklenebilir.

Derleme, classpath ve JAR

  • Paketler, derlenmiş .class dosyalarının klasör yapısına yansır (com/egitim/...).
  • CLASSPATH, JVM'in sınıfları nerede arayacağını söyler.
  • Bir kütüphane, paketler hâlinde düzenlenmiş sınıfların bir JAR dosyasında paketlenmiş halidir (Build araçları bölümünde gördük).
  • Modül sistemi (JPMS, Java 9+), paketlerin üstünde bir katman daha ekler: hangi paketlerin dışa açılacağını (exports) module-info.java ile belirtirsin (ileri konu).

Özet

Paketlerin sınıfları nasıl gruplayıp isim çakışmalarını önlediğini; package bildirimini ve FQN'i; import ile kısa kullanımı ve isim çakışması çözümünü (Örnek 1); static import'u (Örnek 2); paket-özel erişimi, classpath ve JAR ilişkisini öğrendik. Düzenli paket yapısı, büyük projeleri yönetilebilir kılar. Sırada, nesneler arası "sahip olma" (HAS-A) ilişkisi: aggregation ve composition.

Kod Örnekleri(2)

Ornek1

çalıştırılabilir
Ornek1.java
1// Ornek1: import, tam nitelikli ad (FQN) ve isim çakışması çözümü.
2// Paketler, sınıfları gruplar ve isim çakışmalarını önler.
3// Çalıştırma: java Ornek1.java
4import java.util.ArrayList;   // java.util paketinden ArrayList'i içe aktar
5import java.util.List;
6import java.util.Date;        // java.util.Date'i içe aktardık
7
8public class Ornek1 {
9
10    public static void main(String[] args) {
11        // import sayesinde kısa adla kullanırız:
12        List<String> liste = new ArrayList<>();
13        liste.add("paket");
14        liste.add("import");
15        System.out.println("java.util.List: " + liste);
16
17        // import edilmiş java.util.Date kısa adla:
18        Date utilTarih = new Date(0L);
19        System.out.println("java.util.Date: " + utilTarih.toInstant());
20
21        // İSİM ÇAKIŞMASI: java.sql.Date de var. İkisini aynı anda kısa adla kullanamayız;
22        // birini TAM NİTELİKLİ AD (fully-qualified name) ile yazarız.
23        java.sql.Date sqlTarih = new java.sql.Date(0L);
24        System.out.println("java.sql.Date : " + sqlTarih);
25
26        // Hiç import etmeden de tam adla kullanılabilir (uzun ama net):
27        java.math.BigDecimal para = new java.math.BigDecimal("19.99");
28        System.out.println("java.math.BigDecimal: " + para);
29
30        System.out.println("""
31
32                --- Paketler ve import ---
33                Paket = sınıfları gruplayan bir isim alanı (namespace), örn. java.util, com.egitim.app.
34                import: bir sınıfı kısa adıyla kullanmayı sağlar (java.util.List -> List).
35                Tam nitelikli ad (FQN): paket + sınıf (java.sql.Date). İsim çakışmasını çözer.
36                java.lang paketi (String, System, Math...) otomatik içe aktarılır; import gerekmez.""");
37    }
38}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek2

çalıştırılabilir
Ornek2.java
1// Ornek2: static import — bir sınıfın statik üyelerini kısa adla kullanmak.
2// Çalıştırma: java Ornek2.java
3import static java.lang.Math.PI;
4import static java.lang.Math.sqrt;
5import static java.lang.Math.pow;
6import static java.util.stream.Collectors.toList;
7
8import java.util.List;
9import java.util.stream.Stream;
10
11public class Ornek2 {
12
13    public static void main(String[] args) {
14        // static import sayesinde Math.PI / Math.sqrt yerine doğrudan PI / sqrt yazarız.
15        double yaricap = 3;
16        System.out.println("Daire alanı (PI * r^2): " + (PI * pow(yaricap, 2)));
17        System.out.println("Karekök 144          : " + sqrt(144));
18
19        // Collectors.toList -> toList (static import)
20        List<Integer> kareler = Stream.of(1, 2, 3, 4).map(n -> n * n).collect(toList());
21        System.out.println("Kareler: " + kareler);
22
23        System.out.println("""
24
25                --- static import ---
26                Normal import: bir SINIFI içe aktarır (Math).
27                static import: bir sınıfın STATİK üyelerini (PI, sqrt) doğrudan kullanmayı sağlar.
28                Faydası: matematik/yardımcı/test (assertEquals) kodunda okunabilirlik.
29                Dikkat: aşırı kullanım kafa karıştırır (bu metot nereden geliyor?); ölçülü kullan.""");
30    }
31}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.