Java bir source dosyasının içerisine sizin içerisine eklemenizi sağlayan ek bilgi sağlayan bir özellik destekler.Bu bilgi , annotations olarak adlandırılır , programın aksiyonlarını değiştirmez.Böylece , bir annotation (açıklama) bir programın anlamını değiştirmeden bırakır.Ancak , bu bilgi development ve deployment sırasında çeşitli tools tarafından kullanılabilir.Örneğin , bir annotation bir source-code generator (kaynak kod üretici) tarafından işlenebilir.metadata terimi terimi ayrıca bu özelliğe atıfta bulunur , ama annotation terimi daha çok açıklayıcı ve daha fazla yaygın bir şekilde kullanılır.
Annotation Temelleri:
Bir annotation interface tabanlı bir mekanizma vasıtasıyla oluşturulur.Bir örnekle başlayalım.MyAnno isimli bir annotationumuz burada var :
@interface MyAnno{ String str(); int val(); }
Öncelikle , @ interface keywordünden önce geldiğine dikkat edin.Bu compilera şunu söyler bir annotation türü bildiriliyor.Sonra , str() ve val() üyelerine dikkat edin.Tüm annotationslar sadece method declarationlardan oluşur.Ancak , bu methodlar için body(gövde) sağlamazsınız.Bunun yerine , Java bu methodları implement ediyor.Üstelik bu methodlar , ilerde göreceğiniz gibi , daha çok fields gibi davranırlar.Bir annotation extends keywordünü dahil edemez.Ancak , bütün annotation türleri otomatik olarak Annotation arayüzünü genişletir.Böylece , Annotation bütün annotationların bir super-interfacedir.Annotation interfacesi java.lang.annotation packagenin altında tanımlanmıştır.Annotation interfacesi , Object classı tarafından tanımlanmış hashCode(),equals() ve toString() methodlarını override eder.Ayrıca çağrılan annotationun türünü temsil eden , bir Class nesnesi geri döndüren bir annotationType() methodunu da belirtiyor.
Bir kere bir annotation tanımladığınızda , onu bir şeyi açıklamak için kullanabilirsiniz.Örneğin , sınıflar , methodlar , alanlar(fields) , parametreler ve enum sabitleri açıklanabilir(annotated olabilir) .Herhangi bir bildirim türü kendisiyle ilişkili olan bir açıklamaya(annotation) sahip olabilir.Bir annotation(açıklama) bile annotate (açıklanabilir) olabilir.Tüm durumlarda , annotation bildirimin kalanından önce gelir.
Bir annotation uyguladığınızda , onun üyelerine değerler verirsiniz.Örneğin , MyAnno'nun bir method bildirimine uygulanmış bir örneği var :
@MyAnno(str = "Burasi string yeri , Kerem",val = 1240) public static void myMethod() { // kodlar }
Bu annotation myMethod ile bağlıdır.Annotation syntaxına daha yakından bakın.Annotation ismi , @ daha önce gelir tabi , ardından parantez içinde üyelerin başlatmalarının listesi gelir.Bir üyeye değer vermek için , üyenin isimne bir değer atanır.Bu nedenle , bu örnekte , string değeri "Burasi string yeri , Kerem" MyAnno'un str üyesine atandı.Bir annotation üyesine bir değer verildiğinde , sadece onun ismi kullanılır.
Saklama Politikası Belirtme :
Annotationslarda daha ileri gitmeden önce , annotation retention policies(açıklama saklama politikaları)'nı tartışmak gereklidir.Bir saklama politikası hangi noktada bir annotationun atıldığını belirler.Java 3 politika tanımlıyor , bunlar java.lang.annotation.RetentionPolicy enumeration içinde encapsule edilmiştir.Bunlar SOURCE,CLASS ve RUNTIME'dir.
SOURCE saklama politikasına sahip bir annotation sadece kaynak dosyada tutulur ve derleme sırasında atılır.
CLASS saklama politikasına sahip bir annotation delerme sırasında .class dosyası içerisinde saklanır.Ancak , run time sırasında JVM tarafından kullanılmaz.
RUNTIME saklama politikasına sahip bir annotation derleme sırasında .class dosyası içerisinde depo edilir ve run time sırasında da JVM tarafından kullanılır.En büyük annotation kalıcılığını RUNTIME saklama polikitası sunar.
Note : Bir local variable bildiriminde bir annotation .class dosyası içerisinde tutulmaz.
Bir saklama (retention) politikası Java'nın built-in annotationslarından biri olan @Retentionu kullanarak belirtilir.Genel şekli aşağıda gösterildiği gibidir :
@Retention(retention-policy)
Burda , retention-policy önceden tartıştığımız enumeration sabitlerinden biri (SOURCE,CLASS,RUNTIME)olmak zorundadır.Eğer bir annotation için hiç bir saklama politikası belirtilmemişse , o zaman default politika olan CLASS kullanılır.
MyAnno'un aşağıdaki versiyonu RUNTIME saklama politikasını belirtmek için @Retention 'u kullanıyor.Böylece , MyAnno programın çalışması sırasında da JVM tarafından kullanılabilecek.
@Retention(RetentionPolicy.RUNTIME) @interface MyAnno{ String str(); int val(); }
Yansımanın (Reflection) Kullanımı Sayesinde Run Time da Annotationları Elde Etme :
Annotationlar çoğulukla diğer development or deployment toolları tarafından kullanmak için kullanılmak üzere tasarlanmış olsa da, eğer ki RUNTIME saklama politikasını belirtirlerse , o zaman onlar reflectionun kullanımı sayesinde herhangi bir Java programı tarafından run time da sorgulanabilirler.Reflection(Yansıma) run time da bir class hakkında bilgi elde etmeyi sağlar.Reflection API java.lang.reflect packagenin içerisindedir.Reflection kullanımının bir çok yolu var , onların hepsini burada incelemeyeceğiz.Ancak , annotationslara uygulayacağımız bir kaç tane örnek yapacağız.
Reflection kullanının ilk adımı , sizin elde etmek istediğiniz annotationları temsil eden sınıfın Class nesnesini elde etmektir.Class java.lang içerisinde tanımlanmış ve Java'nın built-in sınıflarından biridir.Bir Class nesnesini elde etmek için çok fazla çeşitli yol var.Bunlardan en kolayı Object sınıfı tarafından tanımlanış method olan getClass() methodur.Genel şekli burada gösterilmiştir :
final Class<?> getClass( )
Çağrıldığı nesneyi temsil eden Class nesnesini geri döndürür.
Bir Class nesnesi elde ettikten sonra , sınıf tarafından declare edilmiş çeşitli öğeler hakkında , onun annotationları da dahil, bilgi elde etmek için onun methodlarını kullanabilirsiniz.Bir sınıfın içerisinde specific bir öğe ile bildirilmiş ilişkili annotationları elde etmek istiyorsanız , öncelikle o öğeyi temsile eden bir nesneyi elde etmek zorundasınız.Örneğin , Class sırasıyla bir method,field ve constructor hakkında bilgi elde etmek için getMethod(),getField() ve getConstructor() methodlarını destekler.
Süreci anlamak için , bir method ile ilişkili annotationları elde etmek için bir örnek verelim.Bunu yapmak için, öncelikle sınıfı temsil eden bir Class nesnesini elde edelim , ve sonra Class nesnesi üzerinde , methodun ismini belirterek , getMethod() çağıralım.getMethod() bu genel şekle sahiptir :
Method getMethod(String methodName, Class<?> ... paramTypes)
Methodun ismi methName geçildi.Eğer ki method argümanlara sahipse , o zaman Class nesneleri bu türleri paramTypes tarafından ayrıca belirtmiş olmalı.paramTypes'ın bir varargs parametresi olduğuna dikkat edin.Bu sizin , sıfır da dahil , ihtiyacınız olabilecek kadar çok parametre türünü belirtebileceğiniz anlamına gelir.getMethod() methodu temsil eden bir Method nesnesi geri döderiyor.Eğer ki method bulunamazsa , NoSuchMethodException fırlatılır.
Bir Class,Method,Field yada Constructor nesnesinden , getAnnotation() methodunu çağırarak o objeyle ilişkili belirli bir annotation elde edebilirsiniz.Onun genel formu aşağıda gösterildiği gibidir :
<A extends Annotation> getAnnotation(Class<A> annoType)
Burda annoType sizin ilgilendiğiniz annotationu temsil eden bir Class nesnesidir.Method annotationa bir referansı geri döndürür.Bu referansı kullanarak , annotationun üyeleriyle ilişkili değerleri elde edebilirsiniz.Eğer ki annotation bulunmazsa method null geri döndürür , eğer ki annotation RUNTIME saklama politikasına da sahip değilse yine null geri dönderecek.
Aşağıda önceki konuları anlattığımız bir örnek var ve bu örnek de reflectionu kullanıyo hemen bir örneğe bakalım :
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; @Retention(RetentionPolicy.RUNTIME) @interface MyAnno { String str(); int val(); }class Meta{ @MyAnno(str="Benim Kerem",val = 32) public static void myMethod(){ Meta ob = new Meta(); try{ Class<?> c = ob.getClass(); Method m = c.getMethod("myMethod"); MyAnno myAnno = m.getAnnotation(MyAnno.class); System.out.println(myAnno.val()+" "+myAnno.str()); }catch(NoSuchMethodException exc){ System.out.println("Method Not Found."); } }
<span style="color:#cc7832">public static void </span><span style="color:#ffc66d">main</span>(String[] args) { <em>myMethod</em>()<span style="color:#cc7832">;
} }
Çıktı :
32 Benim Kerem
Arkadaşlar hemen bir sonraki derste Annotationlara devam ediyoruz.