Inner Sınıflar

Inner sınıflar, önceki konularımızdan static yapılar içerisinde sözü geçmiş, fakat detayına değinmediğimiz yapılardandır. İsminden de çıkarım yapılabileceği gibi, inner sınıflar, sınıf içerisine yazılmış sınıflardır. 16 – Inner Classes isimli projemizle bu konuya değineceğiz.

Erişim düzenleyiciler konusundan bildiğimiz üzere javada methodlara veya sınıflara farklı erişim seviyeleri tanımlamak mümkündür. Ancak br sınıf private olarak tanımlanamaz. Zaten private tanımlanmış bir sınıf erişime kapalı olacağından tanımlanması da anlamsız olacaktır. Ancak biz bazı yapıları private tanımlamak istiyorsak ve bu yapılar methodlarla ve değişkenlerle tek başına ifade edilemeyecek kadar karışık ise ne yapabiliriz? Yani ihtiyaç aslında bir sınıf ise ve bunun kısıtlı bir kullanıma sahip olmasını istiyorsak durumu nasıl yönetebiliriz? Burada devreye inner sınıflar girer.

Bu yazımız için tekrar araba markalarına dönüş yapalım. Bir araba arayüzü düşünelim ve bu arayüzün iki ayrı implementasyonu olsun.

public interface Car {

}

public class Ferrari implements Car {

}

public class AstonMartin implements Car {

}

Bunların üzerine bir de utility sınıflar kurgulayalım. Örneğin her iki markanın da kendine has utility sınıfları olsun. Ancak burada odaklanacağımız konu, bu utility sınıflarına, sadece ilgili markanın erişim sağlayacağını garanti altına almaktır. Yani Ferrari utilitysine Ferrari sınıfı, Aston Martin utilitysine Aston Martin erişim sağlayabilsin.

Odağımıza Ferrari sınıfını alarak bunu gerçekleştirelim. Ferrari için yazacağımız utility sınıfında motoru çalıştırdığınızı varsayacağımız bir method bulunsun. Bu sınıfı bir inner sınıf olarak kodlayalım.

public class Ferrari implements Car {

	public void move() {
		FerrariUtils ferrariUtils = new FerrariUtils();
		ferrariUtils.runEngine();
		System.out.println("Moved very fast!");
	}
	
	private class FerrariUtils { //inner class
		
		public void runEngine() {
			System.out.println("Roaaarrr!");
		}
	}
	
}

Burada görüleceği gibi inner sınıflar, tıpkı normal sınıflar gibi tanımlanır. Aynı zamanda bu sınıflar bir başka sınıf bloğunun içindedir. Normal şartlarda bir java dosyası içerisine iki standart sınıfı birden yazmaya kalkarsanız hata alırsınız. Ancak bu durumda inner sınıflar istisna gösterir. Şimdi bir de bu kodu test edelim.

public class TestClass {

	public static void main(String[] args) {
		
		Ferrari f = new Ferrari();
		f.move();
		
	}
}
Çıktı:
Roaaarrr!
Moved very fast!

Şimdi ise AstonMartin sınıfının inner sınıfına odaklanalım. Ferrariden farklı olarak bu defa inner sınıfımızı public tanımlayacağız. Bu ifade, yazının başındaki “Her marka kendi utility sınıflarına erişsin ve diğerlerine erişemesin” isteği ile ters düşmektedir. Ancak burada yaptığımız örnek, inner sınıfların kullanımlarına dair farklı bir örnek oluşturması amacıyla ele alınmaktadır.

public class AstonMartin implements Car {

	public class AstonMartinUtils {

		public void runEngine() {
			System.out.println("Vruuummm!");
		}
	}

}

Öncekinden farklı olarak, dışarıdan erişilebilir bir inner sınıf yaratmış olduk. Ancak sözdizim olarak bu sınıfa, standart ifadelerle doğrudan erişemeyiz. Bu sınıftan bir instance yaratmak için hala AstonMartin sınıfına ihtiyaç duyarız.

AstonMartin a = new AstonMartin();
AstonMartin.AstonMartinUtils au = a.new AstonMartinUtils();
au.runEngine();
Çıktı:
Vruuummm!

Peki ama bunun bize ne faydası oldu? Neden bu utility sınıfını inner olarak tanımladık? Bunun ilk cevabı öncelikle düzenli bir görüntü verebilmek için olacak. Bildiğiniz üzere sınıflar, programlarda karmaşıklaşmayı (spagetti kod) önlemek için kullanacağımız önemli yapıların başında gelir. Bu da bakımı kolaylaşan bir kod anlamına gelecektir. Ayrıca bir inner sınıf, dışarıdaki sınıfın tüm özelliklerini de kullanabilir durumdadır.

public class AstonMartin implements Car {

	private final String brand = "AstonMartin"; 
		
	public class AstonMartinUtils {

		public void runEngine() {
			System.out.println("Vruuummm! " + brand);
		}
		
	}

}

Kodu bu şekilde düzenlediğimizde görürüz ki inner sınıf, üst sınıftaki brand alanına ulaşabilir durumdadır. Üstelik bu alan private durumdadır. Bu noktadan sonrası, karşılaşacağınız durumlara göre hayal gücünüze kalmış durumdadır.

Şimdi Ferrari sınıfımıza geri dönelim. Static yapılar konusunda inner sınıfların da static olabileceğini belirtmiştik. Varsayalım ki Tifosi ismi ile bilinen, Ferrari taraftar kitlesi, bir Ferrari nesnesi veya bir Tifosi nesnesi olmadan da çağırılabilir durumda olsun. Bu örnek için Ferrari sınıfına yeni bir inner class tanımlayacağım.

public class Ferrari implements Car {

	public void move() {
		FerrariUtils ferrariUtils = new FerrariUtils();
		ferrariUtils.runEngine();
		System.out.println("Moved very fast!");
	}

	private class FerrariUtils {

		public void runEngine() {
			System.out.println("Roaaarrr!");
		}
	}

	public static class Tifosi {

		public static void salute() {
			System.out.println("Forza Ferrari!");
		}
	}
}

Bu iç sınıf static olarak tanımlanmıştır. Hatta içerisinde de bir static method vardır. Bu da bir instance olmadan erişilebilir durumda olduklarının göstergesidir. salute() methodunu çağırmak için kodumuz aşağıdaki gibi olacaktır.

Ferrari.Tifosi.salute();
Çıktı:
Forza Ferrari!

Bu örnekte görüyoruz ki static inner sınıfın, static methoduna erişmek için, static olmayan dış sınıfın bir nesnesine ihtiyaç duymadık.

Bu yazımızda da bütün TestClass sınıfını paylaşarak yazıyı sonlandırmak istiyorum. Inner sınıflarla ilgili olarak konumuza dahil olabilcek farklı özellikler veya başlıklar da bulunmaktadır. Ancak yazı serimizin içeriği ile örtüşecek kadar bilgiyi paylaştığımı düşünmekteyim.

public class TestClass {

	public static void main(String[] args) {

		Ferrari f = new Ferrari();
		f.move();

		AstonMartin a = new AstonMartin();
		AstonMartin.AstonMartinUtils au = a.new AstonMartinUtils();
		au.runEngine();
		
		Ferrari.Tifosi.salute();
	}
	
}

Leave a Reply

Your email address will not be published. Required fields are marked *