Static Yapılar

Static anahtar sözcüğü javada bir sınıfla, methodla, değişkenle veya blokla kullanılabilmektedir. Static üyeler sınıftan yaratılmış bir instance yerine, o sınıfın kendisine ait yapılardır. Diğer bir ifade ile, static üyeleri kullanmak için o sınıftan bir instance yaratmaya ihtiyaç yoktur. Bu da static üyelerin, o sınıfa ait bütün instancelarda değerinin veya işleyişinin aynı kalması anlamına gelmektedir.

Static yapılar ile ilgili konularımızı pekiştirmek için 13 – Static isminde bir proje yaratıyoruz. Bunun içerisine öncelikle 2 adet sınıf kodlayacağız. Sınıflardan ilki StringOperations isminde olacak. Diğeri ise her zaman kullandığımız TestClass sınıfı olacak. StringOperations sınıfımızın ilk halini sizinle aşağıda paylaşıyorum.

public class StringOperations {

	public static int counter = 0;

}

Farkedileceği gibi, sınıfın içerisinde sadece bir property tanımı bulunmakta. Ancak öncekilerden farklı olarak static sözcüğüne rastlıyoruz. Bu da counter isimli sınıf üyesinin herhangi bir yerde, o sınıfa ait bir instance olmadan kullanılabileceğini gösterir. Bunun örneğini,test sınıfımızda, doğrudan görelim.

public class TestClass {

	public static void main(String[] args) {
		
		System.out.println("StringOperations.counter:" + StringOperations.counter);
				
	}
	
}
Çıktı:
StringOperations.counter:0

Bu örnekte görüleceği üzere herhangi bir şekilde bir constructor çağrımı yapmadık. Ancak bir sınıfın isminin ardından nokta işareti koyarak, ilgili sınıftaki static bir yapıya ulaştık. Yani sınıfın kendisine ait olup, o sınıftan türetilen bir objeye ait olmayan bir alanı kullandık. Gelin şimdi de bu kısma eğilelim. Bu sınıftan iki ayrı obje yaratıp, o objeler vasıtasıyla bu alana ulaşalım.


public class TestClass {

	public static void main(String[] args) {
		
		System.out.println("StringOperations.counter(1):" + StringOperations.counter);
		
		StringOperations operations1 = new StringOperations();
		StringOperations operations2 = new StringOperations();
		
		System.out.println("operations1.counter(1): " + operations1.counter);
		System.out.println("operations2.counter(1): " + operations2.counter);
		
		operations1.counter = 5;
		
		System.out.println("operations1.counter(2): " + operations1.counter);
		System.out.println("operations2.counter(2): " + operations2.counter);
		System.out.println("StringOperations.counter(2):" + StringOperations.counter);
		
	}
	
}
Çıktı:
StringOperations.counter(1):0
operations1.counter(1): 0
operations2.counter(1): 0
operations1.counter(2): 5
operations2.counter(2): 5
StringOperations.counter(2):5

Bu örnekte 2 ayrı nesnemiz var ve bunlar vasıtası ile ulaşabileceğimiz counter alanını ekrana yazdırıyoruz. İlk durumda (1) hem sınıfın kendisinden bu alanı çağırdığımızda, hem de iki obje vasıtasıyla bu alana ulaştığımızda değerin 0 olduğunu görürüz. Görüntü olarak, sınıf tanımı esnasında bu alanın 0 olarak setlendiği (her instance için ayrı ayrı) düşüncesine kapılabiliriz. Ancak operations1 nesnesinin üzerindeki counter değerini 5 ile setlediğimizde işler biraz değişir. İkinci durumda verdiğimiz düm çıktılar, counter değerinin 5 olduğunu gösterir. Bu da şu anlama gelir: Bir static üye, sınıfa ait nesnelerden bağımsız olarak hareket eder. Bu üye güncellendiğinde herkes için güncellenmiştir.

TestClass içerisinde yaptıklarımızı, yine TestClass içerisinde bir methoda alalım. Methodumuzun ismi staticExamples1() olsun ve geriye değer dönmesin. Ardından main methodu içerisinde bu yeni methodu çağıralım.

Bunu yaptığımızda hata alırız. Bu hatanın sebebi çağırmak istediğimiz methodun static olmamasıdır. Yani static bir method içerisinden (main methodu statictir) başka bir method çağrısı yapıyorsanız, ya o methodun sınıfına ait bir objeye sahip olmalısınız ya da o methodu da static hale getirmelisiniz. Biz bu örnekte methodun kendisini static hale getirerek problemi çözeceğiz. Method imzasını aşağıdaki gibi güncelleyerek hatayı giderebilirsiniz.

private static void staticExamples1() {
//...
}

Şimdi de StringOperations sınıfımıza static bir method daha ekleyelim. Bu method içerisine 1 adet input alsın ve geriye değer dönmesin. Ancak sınıf içerisinde bulunan counter alanını kullanarak ekrana verilen inputu yazdırsın.

public static void print(String input) {

	for (int i = 0; i < counter; i++) {
		System.out.println(i + ":" + input);
	}
}

Bu methodu main içerisinde kullanalım. Ancak TestClass sınıfımıza yine bir method ekleyerek bunu gerçekleştirelim. Yeni test methodumuzun adı staticExamples2() olacak. Sınıfımızı aşağıdaki gibi düzenliyoruz.

//...
public static void main(String[] args) {

	//staticExamples1();
	staticExamples2();
		
}
//...
private static void staticExamples2() {
		
	StringOperations.counter = 5;
	StringOperations.print("Tifosi");
	
	StringOperations.counter = 3;
	StringOperations.print("Forza Ferrari!");
	
}
//...
Çıktı:
0:Tifosi
1:Tifosi
2:Tifosi
3:Tifosi
4:Tifosi
0:Forza Ferrari!
1:Forza Ferrari!
2:Forza Ferrari!

StringOperations sınıfımızda bulunan, static print methodumuzun çağrımına dair bir örneği böylece gözlemlemiş olduk. İlk örneğimizde olduğu gibi bu sınıftan bir instance ihtiyacı olmadan static üyeye erişebilir durumdayız. Eğer elimizde, bu sınıfa ait bir obje olsaydı, sonuç yine değişmezdi. Ancak static methodların yeteneğine uygun olarak yeni bir nesne yaratmamayı tercih ettik. Bunlara ek bilgi olarak, static methodlar bir nesne olmadan çalışabildiğinden, static bir method içerisinde, this ve super anahtar sözcükleri kullanılamaz. Zira bu sözcükler birer instance bilgisine işaret etmektedir. Ayrıca static methodlar static olmayan methodları çağıramazken, static olmayan methodlar static methodları çağırabilmektedir.

Bu bilgilerin ardından bir de static bloklara odaklanalım. Bildiğiniz gibi blok ismi verilen ifadeler, süslü parantezler arasına yazılan kod parçalarıdır. Javada static blok ismi verilen bir blok türü bulunmaktadır. Bu bloklarda static alanların değer yüklemeleri yapılır veya ilgili sınıf memorye yüklenirken çalışması istenilen eylemler gerçekleştirilir. Bunun nasıl yapıldığını görmek için StringOperations sınıfımızda bazı düzenlemeler yapalım.

public class StringOperations {

	public static int counter = 0;
	
	public static String message;
	
	public static String key;
	
	static {
		
		message = "StringOperations.message";
		key = initializeKey();
	}

	public static void print(String input) {

		for (int i = 0; i < counter; i++) {
			System.out.println(i + ":" + input);
		}
	}
	
	private static String initializeKey() {
		return "StringOperations.key";
	}
}

Bu örnekte dikkatinizi çekmek istediğim bazı noktalar var. İlk olarak yeni eklediğimiz field tanımlarında herhangi bir değer yükleme (initialization) yapılmadığını görüyoruz. Sonrasında ise static anahtar sözcüğünün hemen ardından bir blok görüyoruz. Bunun anlamı, bu sınıf kullanıma hazır hale geldiğinde bu bloğun çalışması ve ardından içerisindeki işlemleri yapmasıdır. Bu blok içerisinde de static çağrım kuralları devam eder. Yani doğrudan method çağrımı yapmak isterseniz, çağırdığınız method da static olmalıdır. Aksi durumda o sınıftan bir instance oluşturmaya ihtiyaç duyarsınız. Burada key alanı değerinin bir method vasıtasıyla yüklendiğini görürüz. Bu method, bu kurala uygun olarak static tanımlıdır. Ancak methodun erişim düzenleyicisi private olarak gözükmektedir. Erişim düzenleyiciler konusundaki kurallarımız burada da geçerliliğini korur. Dolayısı ile static olsa bile bu methoda başka bir sınıf üzerinden doğrudan erişim sağlayamayız. TestClass vasıtasıyla bu söylediklerimizi gözlemleyelim.

private static void staticExamples3() {
		
	System.out.println(StringOperations.message);
	System.out.println(StringOperations.key);
}
Çıktı:
StringOperations.message
StringOperations.key

Static yapılara son örnek olarak static sınıflardan bahsedelim. Bir sınıf, ancak diğer bir sınıfın inner (içsel, iç, dahili) sınıfı ise static olabilir. Bir sınıf doğrudan static hale getirilemez. Inner veya nested sınıflar daha sonraki konularımızda bahsedeceğimiz bir başlık olduğundan, bu konudaki örnekleri ilgili yazıda bulabilirsiniz.

Leave a Reply

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