Java'da erişim belirleyiciler (public, private, protected ve default), bir sınıfa ait alanların ve metotların hangi sınıflar veya paketler tarafından görülüp kullanılabileceğini belirleyen anahtar kelimelerdir. Bu dört seviye, kodun hangi bölümünün dışarıya açık, hangi bölümünün sınıfın kendi iç işleyişine ait kalacağını tanımlar. Java erişim belirleyiciler konusunu doğru kavramak, hem encapsulation (kapsülleme) mantığını oturtmak hem de gerçek dünyada sürdürülebilir, hatasız çalışan sınıflar tasarlamak için şarttır. Bu yazıda dört erişim seviyesinin farklarından getter/setter yazımına, yaygın hatalardan bu felsefenin arkasındaki mantığa kadar adım adım ilerleyeceğiz.
Java'da Erişim Belirleyiciler Nedir?
Bir Java sınıfı yazarken her alan ve metot dışarıya açık olmak zorunda değildir; bazı bilgilerin yalnızca sınıfın kendisi tarafından değiştirilmesi, bazılarının ise diğer sınıflarca da kullanılabilmesi gerekir. İşte tam burada erişim belirleyiciler devreye girer: bunlar bir alanın veya metodun hangi sınıflardan, hangi paketlerden erişilebilir olacağını belirleyen anahtar kelimelerdir.
Bu kontrol mekanizması olmasaydı, her alan her yerden doğrudan değiştirilebilir olurdu. Bu durum küçük programlarda sorun yaratmasa da, büyüyen bir kod tabanında ciddi bakım sorunlarına yol açar: bir alanın nerede ve nasıl değiştirildiğini takip etmek zorlaşır, beklenmedik yerlerden gelen hatalı atamalar veri bütünlüğünü bozar ve kodun güvenliği zayıflar. Erişim belirleyiciler, bu riski kaynağında keserek her bileşenin sorumluluk sınırını netleştirir.
Java'da dört erişim seviyesi vardır: public her yerden erişime izin verirken, private erişimi yalnızca tanımlandığı sınıfla sınırlar. protected aynı paket ile birlikte farklı paketteki alt sınıflara da izin verir; hiçbir anahtar kelime yazılmadığında geçerli olan default (package-private) seviye ise erişimi yalnızca aynı paket içindeki sınıflarla sınırlı tutar. Bu dört seviyenin birbirinden farkı ve hangi durumda hangisinin tercih edilmesi gerektiği, sonraki bölümlerde somut örneklerle netleşecek.
Public, Private, Protected ve Default Erişim Seviyelerinin Karşılaştırması
Dört erişim seviyesinin kapsamını tek bakışta görmek, hangi durumda hangisini seçmen gerektiğine karar vermeni kolaylaştırır. Aşağıdaki tablo, her seviyenin aynı sınıf, aynı paket, farklı paketteki alt sınıf ve tamamen farklı bir paketten erişilebilirlik durumunu özetler.
| Erişim Seviyesi | Aynı Sınıf | Aynı Paket | Alt Sınıf (Farklı Paket) | Farklı Paket |
|---|---|---|---|---|
| public | Erişilebilir | Erişilebilir | Erişilebilir | Erişilebilir |
| protected | Erişilebilir | Erişilebilir | Erişilebilir | Erişilemez |
| default (package-private) | Erişilebilir | Erişilebilir | Erişilemez | Erişilemez |
| private | Erişilebilir | Erişilemez | Erişilemez | Erişilemez |
- public: herhangi bir sınırlama olmadan her sınıftan ve her paketten erişilebilir; genellikle dışarıya açılması gereken metotlarda kullanılır.
- protected: aynı paketteki sınıflar ve mirasla türetilen alt sınıflar için erişime açıktır.
- default: hiçbir anahtar kelime belirtilmediğinde otomatik uygulanır ve package-private olarak da bilinir; yalnızca aynı paketteki sınıflar erişebilir.
- private: en katı seviyedir; yalnızca tanımlandığı sınıfın içinden erişilebilir, dışarıdan doğrudan görülemez.
Miras ilişkisinde protected seviyesinin özel bir istisnası vardır: normalde farklı paketteki bir sınıf, başka bir paketteki sınıfın iç üyelerine erişemez. Ancak bir sınıf, protected olarak işaretlenmiş bir alanı veya metodu miras alıyorsa, farklı pakette olsa bile bu üyeye kendi nesnesi üzerinden erişebilir. Bu, kalıtım zincirinin işlevselliğini korurken dışarıdan gelen keyfi erişimi engellemeyi amaçlayan dengeli bir tasarımdır.
Encapsulation (Kapsülleme) Neden Önemlidir?

Encapsulation, bir sınıfın alanlarını private yaparak dışarıdan doğrudan erişimi kapatmak ve bu alanlara yalnızca getter/setter metotları üzerinden kontrollü biçimde ulaşılmasını sağlamak anlamına gelir. Örneğin bir banka hesabı sınıfında bakiye alanı doğrudan public olsaydı, herhangi bir kod parçası bu alanı negatif bir değere ya da mantıksız bir tutara çevirebilirdi. Alan private yapılıp bir setBakiye metodu üzerinden değiştirilmesi sağlandığında, bu metodun içine "bakiye negatif olamaz" gibi bir kontrol eklemek mümkün hale gelir ve hesabın tutarlılığı garanti altına alınır.
Aynı mantık bir yaş alanı için de geçerlidir: yaş alanı doğrudan değiştirilebilir olsaydı, negatif ya da anlamsız büyüklükte bir değer atanmasının önüne geçmek zorlaşırdı. Encapsulation sayesinde bu tür kontrolü tek bir noktada, setter metodunun içinde toplamak mümkündür.
Kapsüllemenin sağladığı faydalar şu şekilde özetlenebilir:
- Veri bütünlüğü: alanlara yalnızca belirlenen kurallar çerçevesinde değer atanabilir, geçersiz veri sınıfın içine giremez.
- Bakım kolaylığı: bir alanın nasıl değiştirildiğini kontrol etmek için tek bir metodu incelemek yeterlidir, kod tabanında dağınık arama yapmaya gerek kalmaz.
- Dış bağımlılıkların azalması: sınıfın iç yapısı değiştiğinde, dışarıdaki kodun bundan etkilenmemesi sağlanır; çünkü dış dünya yalnızca getter/setter arayüzüyle iletişim kurar.
Encapsulation, nesne yönelimli programlamanın kalıtım ve çok biçimlilik gibi diğer temel ilkeleriyle birlikte anılan köşe taşlarından biridir ve bu kavramın örneklerle, sistemli bir şekilde öğrenilmesi gerekir. Bu tür temel OOP prensiplerini adım adım, uygulamalı biçimde pekiştirmek isteyenler için canlı Java eğitimi kapsamında bu konular somut projeler üzerinden ele alınır.
Getter ve Setter Metotları Nasıl Yazılır?
Bir alanı private yaptığında, o alana sınıf dışından doğrudan erişim kapanır. Ancak bu, alanın tamamen erişilemez olacağı anlamına gelmez; erişim artık kontrollü bir kapıdan, yani getter ve setter metotlarından geçer. Bu metotları yazarken izlenen yol oldukça standarttır ve Java geliştiricileri arasında ortak bir dil oluşturur.
- Alanı private yap: Sınıfın içindeki her veri alanı varsayılan olarak
privatetanımlanır; dışarıdan doğrudan erişim engellenir. - Getter isimlendirmesi: Değer okuyan metotlar
getX()biçiminde adlandırılır; alanbooleantipteyse gelenek olarakisX()kullanılır (örneğinisActive()). - Setter isimlendirmesi: Değer atayan metotlar
setX(parametre)biçiminde yazılır ve genellikle geriye bir şey döndürmez (void). - Dönüş tipi ve parametre tutarlılığı: Getter'ın dönüş tipi, setter'ın parametre tipi ve alanın kendi tipi birebir aynı olmalıdır; aksi halde derleyici hata verir veya beklenmeyen dönüşümler ortaya çıkar.
- IDE desteği: Günümüzde kullanılan geliştirme ortamlarının büyük çoğunluğu, tanımlanan alanlar için getter ve setter metotlarını otomatik üretme özelliği sunar; bu, yazımı hızlandırır ama isimlendirme ve tip tutarlılığını anlamayı gerektirir.
Aşağıdaki örnek, bir öğrenci sınıfında bu adımların nasıl uygulandığını gösterir:
public class Ogrenci {
private String ad;
private int yas;
public String getAd() {
return ad;
}
public void setAd(String ad) {
this.ad = ad;
}
public int getYas() {
return yas;
}
public void setYas(int yas) {
this.yas = yas;
}
}
Bu yapıda ad ve yas alanlarına dışarıdan doğrudan erişim mümkün değildir; erişim yalnızca getAd(), setAd(), getYas() ve setYas() metotları üzerinden sağlanır. Bunun nedeni basittir: alan doğrudan public olsaydı, sınıfın dışındaki herhangi bir kod parçası o alana istediği değeri atayabilir, sınıfın kendi iç mantığını hiçe sayabilirdi. Metot üzerinden erişim, sınıfın kendi verisi üzerinde söz sahibi olmasını garanti eder.
Getter/Setter İçine Validasyon Ekleyerek Veri Bütünlüğünü Korumak

Getter ve setter'ların asıl gücü, sadece alana erişim sağlamaktan çok, bu erişim sırasında kontrol uygulayabilmesinden gelir. Bir alanı public bırakırsan, o alana geçersiz bir değer atanmasını engelleyecek hiçbir mekanizman olmaz. Setter kullanınca ise, değeri atamadan önce mantık kontrolü ekleyebilirsin.
Önceki Ogrenci sınıfındaki setYas() metodunu, negatif bir yaş değerinin sisteme girmesini engelleyecek şekilde genişletelim:
public void setYas(int yas) {
if (yas < 0) {
throw new IllegalArgumentException("Yas negatif olamaz: " + yas);
}
this.yas = yas;
}
Bu örnekte, setter metoduna gelen değer önce kontrol edilir; kural ihlal edildiğinde IllegalArgumentException fırlatılarak hatalı verinin nesneye kaydedilmesi baştan engellenir. Bu tür bir kontrolü doğrudan bir public alan üzerinde yapmak mümkün değildir, çünkü alan public olduğunda ona atanan her değer, herhangi bir denetimden geçmeden doğrudan belleğe yazılır. Setter, tam olarak bu noktada devreye girip veriye giriş kapısı görevi görür ve alanın her zaman tutarlı, güvenilir bir durumda kalmasını sağlar.
Bu mantığı gerçek bir projede uygularken, hangi alanlara ne tür kurallar koyulacağı, hangi durumda özel bir istisna sınıfı tanımlanması gerektiği gibi kararlar genellikle ilk başta kafa karıştırıcı olabilir. Bu noktada bire bir geri bildirim almak öğrenme sürecini hızlandırır; birebir Java dersleri kapsamında bu tür validasyon senaryoları gerçek kod örnekleri üzerinden ödev ve proje bazlı olarak pekiştirilebilir. Böylece kavram yalnızca teoride kalmaz, kendi yazdığın sınıflarda somut bir alışkanlığa dönüşür.
Erişim Belirleyicilerde Yaygın Hatalar
Erişim belirleyicileri doğru kullanmak, sadece sözdizimini bilmekten çok, ne zaman hangi seviyeyi seçeceğine dair sağlam bir sezgi geliştirmeyi gerektirir. Yeni başlayanların sıkça düştüğü bazı hatalar, ilerleyen aşamalarda ciddi bakım sorunlarına yol açabilir.
- Gereksiz yere alanları public bırakmak: Bu, sınıfın iç verisinin dışarıdan kontrolsüzce değiştirilmesine izin verir; sonuç olarak veri bütünlüğü bozulur ve hata ayıklaması zor bug'lar ortaya çıkar.
- Her şeyi aşırı private yapıp gerekli erişimi de engellemek: Alt sınıfların veya ilişkili sınıfların meşru şekilde ihtiyaç duyduğu erişimi bile kapatmak, gereksiz getter/setter yığınına ve karmaşık kod yapısına yol açar.
- Protected'ı gereksiz yere paket-dışı senaryolarda kullanmak: Kalıtım ilişkisi olmayan yerlerde protected seçmek, erişim sınırlarını bulanıklaştırır ve ileride hangi sınıfın neye erişebildiğini takip etmeyi zorlaştırır.
- Getter/setter'ı anlamsızca her alana otomatik eklemek: Değişmemesi gereken ya da dışarıya hiç açılmaması gereken alanlara bile mekanik şekilde erişimci metot yazmak, encapsulation'ın amacını boşa çıkarır ve güvenlik açığı riski oluşturur.
Bu hataların çoğu, kod çalışıyor gibi göründüğü için başlangıçta fark edilmez; sorun genellikle proje büyüdükçe, birden fazla kişi aynı sınıfa dokunmaya başladığında ortaya çıkar. Kendi yazdığın kodda bu tür seçimleri ne kadar bilinçli yaptığını görmek istersen, Java bilgi seviyeni ölçen testi çözerek erişim belirleyiciler ve encapsulation konusundaki eksiklerini net biçimde tespit edebilirsin.
Java'nın Erişim Belirleyici Felsefesi: Geçmişten Günümüze
Java diliyle yeni tanışan biri için ilginç bir gözlem şudur: public, private, protected ve default dörtlüsünün mantığı, dilin ilk sürümlerinden bu yana kavramsal olarak değişmemiştir. Bir alanın veya metodun "kim tarafından görülebileceği" sorusuna verilen cevap yıllar içinde aynı kalmıştır; değişen şey yalnızca bu kuralları daha az kod yazarak uygulamanı sağlayan araçlar ve dil özellikleridir. Bu istikrar tesadüf değildir — Java'nın nesne yönelimli programlama felsefesi başından beri veriyi koruma ve kontrollü erişim ilkesine dayanır, dolayısıyla erişim belirleyicilerin temel mantığını bir kez öğrendiğinde bu bilgi yıllar sonra da geçerliliğini korur.
Bu istikrarlı temelin üzerine dilin zamanla eklediği pratik kolaylıklardan biri record yapılarıdır. Java 14 ile gelen record'lar, immutable (değişmez) veri sınıfları tanımlamak için constructor, equals, hashCode, toString ve erişimci metotlarını otomatik üretir. Bu özellik, sadece veri taşıyan basit sınıflarda getter yazma yükünü belirgin biçimde azaltır; ancak bunu bir "encapsulation'ın yerini alan kısayol" olarak görmek yanlış olur. Record'lar hâlâ private alanlara dayanır ve dışarıya kontrollü erişim sağlar; sadece bu kontrolü senin yerine derleyici otomatik kurar. Klasik bir sınıfta setter yazarak validasyon eklemen gereken senaryolarda ise record'un sunduğu otomatik üretim yeterli olmayabilir, çünkü değiştirilebilir alanlarla çalışman gerekir.
Benzer bir kolaylaştırma günümüz geliştirme ortamlarında (IDE'lerde) de karşımıza çıkar. Çoğu modern IDE, private olarak tanımladığın alanlar için getter ve setter metotlarını otomatik oluşturma özelliği sunar; birkaç tık ile standart erişimci metotlar kod tabanına eklenir. Bu, yazım hızını artıran faydalı bir kolaylıktır — ama otomatik üretilen kodun ne yaptığını anlamadan kullanmak, encapsulation'ın asıl amacını kaçırmak demektir. Bir IDE senin yerine kod yazabilir, fakat hangi alanın private kalması gerektiğine, hangi setter'a validasyon eklenmesi gerektiğine karar veremez. İşte bu noktada, kodu yazmadan önce düşünme alışkanlığı devreye girer: hangi veri korunmalı, hangi kural her zaman geçerli olmalı sorularını cevaplamak, otomatik üretilen kalıpları anlamlı hâle getirir. eğitmenimiz Berk Keskin'in yazılım öğretim yaklaşımı da tam olarak bu noktaya odaklanır: araçları kullanmadan önce kavramı zihinde oturtmak.
Özet: Erişim Belirleyicileri Doğru Kullanmak İçin Ne Yapmalısın?
Bu yazı boyunca gördüğün gibi, Java'da dört erişim seviyesini doğru seçmek ve alanlarını private tutup getter/setter metotlarıyla kontrollü erişim sağlamak, encapsulation'ın (kapsülleme) temelini oluşturur. Bir sınıfın iç verisini doğrudan dışarıya açmak yerine, dışarıdan gelen her okuma ve yazma isteğini kendi kontrolünden geçirmesi, hem hata riskini azaltır hem de kodun uzun vadede bakımını kolaylaştırır. Bu prensip; küçük bir öğrenci projesinde de, büyük bir kurumsal yazılımda da aynı şekilde işler.
Bu bilgiyi kalıcı hâle getirmenin en etkili yolu, öğrendiğin kuralları küçük alıştırmalarla tekrar tekrar uygulamaktır. Bir sınıf tanımla, alanlarını private yap, getter/setter yaz, sonra bir arkadaşınla veya bir eğitmenle bu kodu gözden geçir; başkasının bakış açısıyla aldığın geri bildirim, kendi kendine fark edemeyeceğin hataları görmeni sağlar. Encapsulation gibi kavramlar teoride basit görünse de, gerçek kod üzerinde pratik yapmadan tam anlamıyla oturmaz.
Eğer bu noktada Java öğrenimini bir kariyer hedefiyle ilişkilendirmek istiyorsan, hangi yönde ilerlemenin sana daha uygun olduğunu görmek faydalı bir adım olabilir. ücretsiz kariyer keşif testi, yazılım geliştirme yolculuğunda hangi alanlara doğal bir yatkınlığın olduğunu görmene yardımcı olabilir. Erişim belirleyiciler ve encapsulation gibi temel kavramları sağlam öğrenmek, ileride hangi teknolojiyle veya hangi projeyle çalışırsan çalış, seni bir adım öne taşıyacaktır.
Sık Sorulan Sorular
Java'da default (package-private) erişim belirleyici ne zaman kullanılır?
Default erişim, aynı paket içindeki sınıfların birbirine yakın çalışması gerektiğinde tercih edilir. Bir sınıfın sadece kendi paketi içinde kullanılacak yardımcı metotları veya alanları varsa, bunları public yaparak dışarıya açmak yerine hiçbir erişim belirleyici yazmadan default seviyede bırakmak, paket dışına gereksiz bağımlılık oluşmasını engeller.
Getter ve setter yazmak zorunlu mudur, doğrudan public alan kullansam olmaz mı?
Teknik olarak bir alanı public yapıp doğrudan erişime açmak mümkündür, ancak bu encapsulation prensibini tamamen devre dışı bırakır. Alan public olduğunda değerin geçerliliğini kontrol edecek hiçbir mekanizma kalmaz; hatalı veya mantıksız bir değer doğrudan atanabilir. Bu yüzden private alan ve getter/setter kullanımı, küçük projelerde bile önerilen bir alışkanlıktır.
Protected erişim belirleyici private'tan farklı olarak neye izin verir?
Private bir alana yalnızca tanımlandığı sınıfın içinden erişilebilirken, protected bir alana aynı paketteki sınıflar ve farklı paketteki alt sınıflar (kalıtım ilişkisi olan sınıflar) da erişebilir. Yani protected, kalıtım senaryolarında alt sınıflara belirli bir esneklik tanımak için kullanılır.
Encapsulation ile abstraction (soyutlama) arasındaki fark nedir?
Encapsulation, verinin nasıl saklandığını ve korunduğunu gizlemeye odaklanır; private alanlar ve getter/setter bu prensibin somut uygulamasıdır. Abstraction ise bir nesnenin "ne yaptığını" gösterip "nasıl yaptığını" gizlemeye odaklanır; genellikle arayüzler (interface) veya soyut sınıflarla ifade edilir. İkisi birlikte çalışır ama çözdükleri sorun farklıdır.
Her private alan için mutlaka hem getter hem setter yazmalı mıyım?
Hayır. Eğer bir alanın dışarıdan değiştirilmesini istemiyorsan, o alan için yalnızca getter tanımlayıp setter yazmayabilirsin; bu, alanı okunabilir ama değiştirilemez (read-only) hâle getirir. Setter yazıp yazmama kararı tamamen o verinin iş mantığına göre verilmelidir.
IDE'lerin otomatik ürettiği getter/setter kodlarına güvenebilir miyim?
IDE'lerin ürettiği standart getter/setter kalıpları teknik olarak doğrudur ve güvenle kullanılabilir. Ancak bu otomatik üretilen kod, veri doğrulama (validasyon) gibi iş kurallarını içermez; validasyon eklemek istiyorsan üretilen setter metodunu elle düzenlemen gerekir.
Java'da erişim belirleyici belirtilmezse ne olur?
Bir sınıf, alan veya metot tanımlanırken hiçbir erişim belirleyici yazılmazsa, Java bunu otomatik olarak default (package-private) erişim seviyesinde kabul eder. Bu durumda ilgili öğeye yalnızca aynı paket içindeki sınıflar erişebilir.
Erişim belirleyiciler ve getter/setter kullanımı, Java'da sağlam ve sürdürülebilir kod yazmanın en temel yapı taşlarından biridir; bu kavramları iyi anlayan bir geliştirici, ilerideki her projede daha güvenli ve okunabilir kod üretir. Öğrendiklerini pekiştirmek ve seviyeni ölçmek istersen Java bilgi testi ile kendini kısa sürede değerlendirebilirsin.