![translation](https://cdn.durumis.com/common/trans.png)
Bu, AI tarafından çevrilen bir gönderidir.
Dil Seç
Text summarized by durumis AI
- Yansıma, çalışma zamanında sınıf bilgilerine erişerek sınıfları istediğiniz gibi manipüle etmenizi sağlayan bir API'dir.
- Yansıma aracılığıyla sınıf örnekleri oluşturabilir ve alanlara ve yöntemlere erişim kontrolcülerinden bağımsız olarak erişebilirsiniz, özellikle çerçeveler gibi büyük ölçekli geliştirme aşamalarında bağımlılıkları dinamik olarak yönetmek için yararlıdır.
- Ancak kapsüllemeyi ihlal edebilir ve performans düşüşüne neden olabilir, bu nedenle yalnızca gerektiğinde kullanmanız önerilir.
Yansıma Nedir?
Yansıma, yığın alanında yüklenen Class türündeki nesneler aracılığıyla istenen sınıfın örneklerini oluşturmayı destekleyen ve örneklerin alanlarına ve yöntemlerine erişim kontrolcülerinden bağımsız olarak erişmeyi sağlayan bir API'dir.
Burada yüklenen sınıf, JVM'nin sınıf yükleyicisinin sınıf dosyalarını yüklemesini tamamladıktan sonra ilgili sınıfın bilgilerini içerenClass türündeki bir nesneoluşturup belleğin yığın alanında depolamayı ifade eder. new anahtar sözcüğüyle oluşturulan nesnelerle aynı olmadığına dikkat edin. Eğer Class türündeki nesneleri anlamıyorsanız, java.lang.class nesnesinin JDK belgelerine göz atmanız yararlı olacaktır.
Kullanım Şekli
Yansıma kullanmadan önce, yığın alanında yüklenen Class türündeki nesneleri almanız gerekir. Toplam 3 yöntem vardır.
- Sınıf.class kullanarak almak
- Örnek.getClass() kullanarak almak
- Class.forName("SınıfAdı") kullanarak almak
public class Member {
private String name;
protected int age;
public String hobby;
public Member() {
}
public Member(String name, int age, String hobby) {
this.name = name;
this.age = age;
this.hobby = hobby;
}
public void speak(String message) {
System.out.println(message);
}
private void secret() {
System.out.println("Şifre 1234'tür.");
}
@Override
public String toString() {
return "Member{" +
"name='" + name + '\'' +
", age=" + age +
", hobby='" + hobby + '\'' +
'}';
}
}
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class memberClass = Member.class;
System.out.println(System.identityHashCode(memberClass));
Member member = new Member("Jayon", 23, "Darath geliştirme");
Class extends Member> memberClass2 = member.getClass();
System.out.println(System.identityHashCode(memberClass2));
Class> memberClass3 = Class.forName("{paket adı}.Member");
System.out.println(System.identityHashCode(memberClass3));
}
}
// Çalıştırma Sonucu
1740000325
1740000325
3 yöntemle alınan Class türündeki örneklerin hepsinin aynı olduğunu görebilirsiniz. Hangi yöntemi kullanırsanız kullanın, karma değer aynıdır, bu nedenle duruma göre uygun olanı kullanabilirsiniz.
Şimdi, alınan Class türü aracılığıyla ilgili sınıfın örneklerini oluşturabilir ve örneklerin alanlarına ve yöntemlerine erişim kontrolcülerinden bağımsız olarak erişebilirsiniz. Önce ilgili sınıfın örneklerini oluşturalım.
public class Main {
public static void main(String[] args) throws Exception {
// Member'ın tüm yapıcılarını yazdır
Member member = new Member();
Class extends Member> memberClass = member.getClass();
Arrays.stream(memberClass.getConstructors()).forEach(System.out::println);
// Member'ın varsayılan yapıcısını kullanarak bir örnek oluştur
Constructor extends Member> constructor = memberClass.getConstructor();
Member member2 = constructor.newInstance();
System.out.println("member2 = " + member2);
// Member'ın diğer yapıcılarını kullanarak bir örnek oluştur
Constructor extends Member> fullConstructor =
memberClass.getConstructor(String.class, int.class, String.class);
Member member3 = fullConstructor.newInstance("Jayon", 23, "Darath geliştirme");
System.out.println("member3 = " + member3);
}
}
// Çalıştırma Sonucu
public Member()
public Member(java.lang.String,int,java.lang.String)
member2 = Member{name='null', age=0, hobby='null'}
getConstructor() aracılığıyla yapıcıyı alabilirsiniz ve newInstance() aracılığıyla Member örneğini dinamik olarak oluşturabilirsiniz.
Son olarak, örneğin alanlarına ve yöntemlerine erişim kontrolcülerinden bağımsız olarak erişerek kullanmayı deneyelim.
public class Main {
public static void main(String[] args) throws Exception {
Member member = new Member("Jayon", 23, "Darath geliştirme");
Class extends Member> memberClass = member.getClass();
// Alana erişim
Field[] fields = memberClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
System.out.println(field.get(member));
}
fields[0].set(member, "Jayon2");
System.out.println(member);
// Yönteme erişim
Method speakMethod = memberClass.getDeclaredMethod("speak", String.class);
speakMethod.invoke(member, "Yansıma testi");
Method secretMethod = memberClass.getDeclaredMethod("secret");
secretMethod.setAccessible(true);
secretMethod.invoke(member);
}
}
// Çalıştırma Sonucu
Jayon
23
Darath geliştirme
Member{name='Jayon2', age=23, hobby='Darath geliştirme'}
Yansıma testi
getDeclaredFileds() aracılığıyla sınıfın örnek değişkenlerinin hepsini alabilirsiniz, get() aracılığıyla alan değerini alabilirsiniz ve set() aracılığıyla alan değerini değiştirebilirsiniz. Burada dikkat edilmesi gereken nokta, private erişim kontrolcüsü olan bir alana erişmek için setAccessible()'in parametresine true değerini geçirmeniz gerektiğidir.
Yöntemler de getDeclaredMethod() aracılığıyla alınabilir. Bu durumda, yöntemin adı ve parametrelerin türü birlikte parametre olarak geçirilir. Benzer şekilde, private erişim kontrolcüsü olan bir yönteme erişmek için setAccessible()'in parametresine true değerini ayarlamanız gerekir. Son olarak, invoke() yöntemi aracılığıyla yansıma API'siyle alınan yöntemi çağırabilirsiniz.
Avantajlar ve Dezavantajlar
- Avantajlar
- Çalışma zamanında sınıfın örneklerini oluşturabilir ve erişim kontrolcülerinden bağımsız olarak alanlara ve yöntemlere erişerek gerekli işlemleri gerçekleştirebilir, bu da esneklik sağlar.
- Dezavantajlar
- Kapsüllemeyi ihlal eder.
- Çalışma zamanında örnek oluşturulduğundan, derleme zamanında ilgili türü denetlenemez.
- Çalışma zamanında örnek oluşturulduğundan, belirli çalışma akışını anlamak zorlaşır.
- Sadece alanlara ve yöntemlere erişmek için kullanmak yerine yansıma kullanarak erişmek performans kaybına neden olur. (Her durumda performans düşüklüğü olmaz.)
Kullanılma Nedenleri
Yansıma API'si aracılığıyla, çalışma zamanında sınıf bilgilerine erişebilir ve sınıfı istediğiniz gibi değiştirebilirsiniz. Hatta private erişim kontrolcüsüyle bildirilen alanları ve yöntemleri bile değiştirebilirsiniz. Nesne yönelimli tasarımda kapsülleme önemli olduğundan, bu bir kullanılmaması gereken teknoloji gibi görünebilir.
Küçük ölçekli konsol aşamalarında, geliştiriciler derleme zamanında programda kullanılacak nesneleri ve bağımlılıkları tam olarak anlayabilir. Ancak çerçeveler gibi büyük ölçekli geliştirme aşamalarında, çok sayıda nesne ve bağımlılığı anlamak zor olabilir. Bu durumda, yansıma kullanarak dinamik olarak sınıflar oluşturup bağımlılıkları oluşturabilirsiniz.
Örneğin, Spring'in Bean Factory'sine baktığımızda, @Controller, @Service, @Repository gibi ek açıklamalar eklediğimizde, Bean Factory'nin bu ek açıklamalar eklenen sınıfları otomatik olarak oluşturup yönettiğini görebiliriz. Geliştirici Bean Factory'ye bu sınıfları bildirmemiştir, ancak bunun nedeni yansımadır. Çalışma zamanında, bu ek açıklamalar eklenen sınıflar taranır ve bulunursa yansıma kullanılarak ilgili sınıfın örnekleri oluşturulur, gerekli alanlar eklenir ve Bean Factory'de saklanır.
Elbette, yukarıda belirtildiği gibi kapsüllemeyi ihlal ettiği için yalnızca gerekli olduğunda kullanılması tavsiye edilir.