18 Şubat 2011 Cuma

İlk Java Programı

Adet olduğu üzre, benim de Java günlüğümün ilk yazısı Java programlarının çalıştırılma biçimiyle ilgili. Kaynak kodun makine koduna derlendikten sonra—olası bir bağlama aşamasının ardından—fiziksel makine üzerinde doğrudan işlenerek çalıştırıldığı C/C++, Pascal gibi derlemeli dillerin aksine, Java kaynak kodu derlemeli yorumlama (İng., interpretive compilation) ile çalıştırılır. Buna göre, Java dilinde yazılmış olan bir program önce Bytecode adındaki bir ara dilin komutlarını içeren ve formatı standardize edilmiş sınıf dosyasına çevrilerek sanal bir makine üzerinde yorumlanarak çalıştırılır. Her iki yöntemin de artıları ve eksileri vardır. Ancak, bu konuya girmeden önce derlemeli yorumlamanın nasıl işlediğini aşağıdaki minik örnek üzerinden görelim.

SelamMillet.java
public class SelamMillet {
  public static void main(String[] ksa) {
    System.out.println("Selam millet!");
  } // void main(String[]) sonu
} // SelamMillet sınıfının sonu

Aşağıda olduğu gibi derleyiciye kaynak dosya adının geçirilmesi ile icra edilen derleme aşaması, Java dili kurallarına uygun kodu class uzantılı Bytecode dili komutları içeren sınıf dosyası haline çevirir. [Kaynak kod içinde birden çok sınıfın tanımının yapılması durumunda, her sınıfa karşılık bir sınıf dosyası üretilecektir.]

# Derleme aşaması
$ javac SelamMillet.java
$ ls SelamMillet.*
SelamMillet.class   SelamMillet.java

Sınıf dosyasının oluşturulmasıyla birlikte Java Sanal Makinesi'ne (JSM) geçirilip çalıştırılmasının bir edimli kütüğün çalıştırılmasından aslında çok farkı yoktur. Her iki durumda da derleme sonucunda oluşturulan çalıştırılabilir dosya bir makine üzerinde yorumlanır. Ancak, edimli kütük için yorumlama bir fiziksel makine üzerinde yapılırken, sınıf dosyası için soyut bir makine üzerinde yapılır.

# Yorumlama aşaması
$ java SelamMillet
$ Selam millet!

Çalıştırılabilir sınıf dosyalarının soyut makine tarafından yorumlanması, dosya içeriğini oluşturan Bytecode komutlarının fiziksel makine komutları karşılıklarına dönüştürülmesini takiben bu makine komutlarının fiziksel makine üzerinde işlenmesiyle tamamlanır. Derlemeli dillerde programın çalışması öncesinde yapılan bu dönüşümün varlığı, Java programlarının daha yavaş çalışacağı anlamına gelir. Ancak, bu yavaşlama yorumlanan dilin (Bytecode) bir ara dil olması ve makine diline yüksek düzey dillerden daha yakın olması nedeniyle safkan yorumlamadaki kadar fazla olmayacaktır. Ayrıca, sanal makinenin yazılımda gerçekleştirilmesi ve Bytecode dili ile sınıf dosyası formatının standardize edilmiş olması, sınıf dosyalarının JSM'ne sahip tüm donanımlarda çalıştırılabileceği anlamını taşır. Yani, program çalışma hızındaki yavaşlamaya karşılık, nesne kodu düzeyinde taşınabilirlik elde edilmiştir.

Çalışma hızındaki yavaşlama, Java dilinde yazılmış programları doğrudan makine diline çeviren bir derleyici—mesela, gcj—ile aşılabilir. Platforma özel yazılımların üretiminde kabul edilebilirse de, Java'nın taşınılmazlığın vazgeçilmez olduğu İnternet ortamının dili olarak lanse edildiği düşünüldüğünde, çoğu kullanım senaryosu için taşınabilirliği olanaksız kılan bu seçenek uygulanabilir olmayacaktır. Dolayısıyla, taşınabilirlikten vazgeçmeyen bir çözümün tercih edilmesi daha yerinde olacaktır. Aranan çözüm, hemen hemen tüm JSM'lerinin desteklediği anında derlemeden geçer. Programcı/kullanıcı açısından  derlemeli yorumlamadan farkı bulunmayan bu çalıştırma yönteminde  JSM, Bytecode komutlarını yorumlarken bazı eniyilemeler yapar. Örneğin, ilk kez çağrılan bir metodun ilk çağrısı sırasında sonraki çağrıların daha hızlı olması için söz konusu metot veya metodun bulunduğu sınıf o noktada makine koduna çevrilerek bir önbelleğe yerleştirilir. Sonraki çağrılar, silinmediyse  önbellekteki derlenmiş kodu kullanacak ve programın çalışma hızı makine koduna derlenen programlarınkine benzer  bir düzeye çıkacaktır.

Özetlemek gerekirse; Bytecode komutları içeren sınıf dosyalarına derlenen Java kaynak kodu, bu sınıf dosyalarının anında derleme desteğiyle yorumlanması sayesinde nesne kodu düzeyindeki taşınabilirlik özelliğini yitirmeden hızlı bir şekilde çalıştırılır.