Soru Yansıma nedir ve neden yararlıdır?


Yansıma nedir ve neden yararlıdır?

Özellikle Java ile ilgileniyorum, ama prensiplerin her dilde aynı olduğunu varsayalım.


1696
2017-09-01 08:39


Menşei


Benim için sınıf adlarını çalışma zamanında elde etmenin ve o sınıfın nesnelerini oluşturmanın bir yolu. - Nabin
çünkü bu popüler bir sorudur çünkü bu yansımayı (ek açıklama olmadan) bir problemi çözerken kullanacağınız son araç olmalıdır. Onu kullanıyorum ve seviyorum, ama Java'nın statik yazımının tüm avantajlarını iptal ediyor. İhtiyacınız varsa, mümkün olduğu kadar küçük bir alana ayırın (Bir yöntem veya bir sınıf). Testlerde üretim kodundan daha kullanışlıdır. Ek açıklamalarla iyi olmalı - Ana nokta, sınıf veya yöntem isimlerini "Dizeler" olarak tanımlamaktan kaçınmanız mümkün değildir. - Bill K
Ayrıca bakınız: softwareengineering.stackexchange.com/questions/123956/... - givanse


Cevaplar:


İsim yansıması, aynı sistemde (veya kendisinde) başka kodları denetleyebilen kodu tanımlamak için kullanılır.

Örneğin, Java'da bilinmeyen bir nesneye sahip olduğunuzu ve varsa bir 'doSomething' yöntemini çağırmak istediğinizi varsayalım. Java'nın statik yazım sistemi, nesne bilinen bir ara yüze uymadıkça bunu yansıtmak için tasarlanmamıştır, ancak yansımayı kullanarak kodunuz nesneyi arayabilir ve 'doSomething' adlı bir yönteme sahip olup olmadığını öğrenebilir ve eğer siz istemek.

Bu yüzden, size Java'da bunun bir kod örneği vermek için (söz konusu nesnenin sanal olduğunu düşünün):

Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);

Java'da çok yaygın kullanılan bir durum, ek açıklamalarla kullanımdır. Örneğin, JUnit 4, @Test notu ile etiketlenmiş yöntemler için sınıflarınıza bakmak üzere yansımayı kullanacak ve daha sonra birim testini çalıştırırken bunları arayacaktır.

Başlamak için bazı iyi yansıma örnekleri var. http://docs.oracle.com/javase/tutorial/reflect/index.html

Ve son olarak, evet, kavramlar, yansımayı destekleyen diğer statik türlerde oldukça benzerdir (C # gibi). Dinamik olarak yazılan dillerde, yukarıda açıklanan kullanım durumu daha az gereklidir (derleyici herhangi bir yöntemin herhangi bir nesnede çağrılmasına izin vereceğinden, çalışma zamanında çalışmazsa başarısız olur), ancak işaretlenen yöntemlerin ikinci durumu belli bir şekilde çalışmak hala yaygındır.

Yorumdan güncelleme:

Sistemdeki kodu denetleme ve nesne tiplerini görme yeteneği   yansıma değil, daha çok Tür Introspection. Yansıma o zaman   kullanımıyla çalışma zamanında değişiklikler yapma yeteneği   introspection. Burada bazı dillerin ayrımı gerekli   içgözlemeyi destekler, ancak yansımayı desteklemez. Böyle bir örnek   C ++


1417
2017-09-01 08:44



Lütfen bu satırdaki null parametresinin öneminin ne olduğunu açıklayabiliriz Method method = foo.getClass (). getMethod ("doSomething", null); - Krsna Chaitanya
Null, foo yöntemine geçirilmiş hiçbir parametrenin olmadığını gösterir. Görmek docs.oracle.com/javase/6/docs/api/java/lang/reflect/..., java.lang.Object ...) detaylar için. - Matt Sheppard
Sadece bu kadar çok upvotes sahip olduğu için temizlemek için. Kodun sistemde denetlenmesi ve nesne türlerini görme yeteneği yansıma değil, Türün İntrospektifi'dir. Yansıma, daha sonra iç gözlemden yararlanarak çalışma zamanında modifikasyon yapma yeteneğidir. Bazı dillerin iç gözlemi desteklediği, ancak yansımayı desteklemediği için ayrım gereklidir. Böyle bir örnek C ++. - bigtunacan
Ben yansımayı seviyorum ama eğer kod üzerinde kontrolünüz varsa, o zaman bu cevapta belirtildiği gibi yansıma kullanmanız uygunsuz ve bu nedenle bir kötüye kullanımdır - Tip Introspection (instanceof) ve güçlü türler kullanmalısınız. Bir şey yapmanın bir yolu var ama yansıma varsa, böyle yapılması gerekiyor. Yansıma, ciddi bir kalp atışına neden olur, çünkü statik olarak yazılan bir dil kullanmanın tüm avantajlarını kaybedersiniz. İhtiyacınız varsa, buna ihtiyacınız var, ancak o zaman bile, Spring gibi önceden ambalajlanmış bir çözümü veya gerekli yansımayı tamamen kapsülleyen bir şey düşünürdüm - IE: başkasının baş ağrısına sahip olmasına izin verin. - Bill K
@bigtunacan Bu bilgiyi nereden aldınız? Oracle'ın resmi Java belgelerinde kullanılan "yansıma" terimini, yalnızca çalışma zamanında değişiklik yapma yeteneğini değil, aynı zamanda bir nesnenin türünü görme yeteneğini de açıklamak için görüyorum. En çok sözde "tip iç gözlem" ile ilgili sınıflardan bahsetmemek (ör: Method, Constructor, Modifier, Field, Membertemelde görünüşte tüm hariç Class) içinde java.lang.*reflect* paketi. Belki de "yansıma" kavramı, hem "tip iç gözlemini" hem de çalışma zamanında modifikasyonu içerir. - RestInPeace


yansıma bir dilin çalışma zamanında sınıfları, yöntemleri, özniteliklerini vb. denetleyip dinamik olarak çağırmasıdır.

Örneğin, Java'daki tüm nesneler yönteme sahiptir getClass()Bu, derleme zamanında bilmese bile nesnenin sınıfını belirleyebilmenizi sağlar (ör. Object) - Bu önemsiz gibi görünebilir, ancak bu tür yansıma, daha az dinamik dilde mümkün değildir. C++. Daha gelişmiş kullanımlar, yöntemleri, kurucuları vb. Listelemenizi ve çağırmanızı sağlar.

Yansıma önemlidir, çünkü derleme zamanında her şeyi "bilmesi" gerekmeyen programları yazmanıza olanak tanır, böylece çalışma zamanında birbirine bağlanabildikleri için onları daha dinamik hale getirir. Kod, bilinen arabirimlere karşı yazılabilir, ancak kullanılacak olan gerçek sınıflar, yapılandırma dosyalarından gelen yansıma kullanılarak başlatılabilir.

Pek çok modern çerçeve, bu sebepten dolayı yoğun bir şekilde yansıma kullanmaktadır. Diğer birçok modern dil de yansımayı kullanır ve betik dillerinde (Python gibi), bu dillerin genel programlama modelinde daha doğal olduğunu düşündüklerinden, daha sıkı bir şekilde bütünleşirler.


195
2017-09-01 08:52





En sevdiğim yansıma kullanımlarından biri, aşağıdaki Java dökümü yöntemidir. Herhangi bir nesneyi bir parametre olarak alır ve her alan adını ve değerini yazdırmak için Java yansıma API'sini kullanır.

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public static String dump(Object o, int callCount) {
    callCount++;
    StringBuffer tabs = new StringBuffer();
    for (int k = 0; k < callCount; k++) {
        tabs.append("\t");
    }
    StringBuffer buffer = new StringBuffer();
    Class oClass = o.getClass();
    if (oClass.isArray()) {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("[");
        for (int i = 0; i < Array.getLength(o); i++) {
            if (i < 0)
                buffer.append(",");
            Object value = Array.get(o, i);
            if (value.getClass().isPrimitive() ||
                    value.getClass() == java.lang.Long.class ||
                    value.getClass() == java.lang.String.class ||
                    value.getClass() == java.lang.Integer.class ||
                    value.getClass() == java.lang.Boolean.class
                    ) {
                buffer.append(value);
            } else {
                buffer.append(dump(value, callCount));
            }
        }
        buffer.append(tabs.toString());
        buffer.append("]\n");
    } else {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("{\n");
        while (oClass != null) {
            Field[] fields = oClass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                buffer.append(tabs.toString());
                fields[i].setAccessible(true);
                buffer.append(fields[i].getName());
                buffer.append("=");
                try {
                    Object value = fields[i].get(o);
                    if (value != null) {
                        if (value.getClass().isPrimitive() ||
                                value.getClass() == java.lang.Long.class ||
                                value.getClass() == java.lang.String.class ||
                                value.getClass() == java.lang.Integer.class ||
                                value.getClass() == java.lang.Boolean.class
                                ) {
                            buffer.append(value);
                        } else {
                            buffer.append(dump(value, callCount));
                        }
                    }
                } catch (IllegalAccessException e) {
                    buffer.append(e.getMessage());
                }
                buffer.append("\n");
            }
            oClass = oClass.getSuperclass();
        }
        buffer.append(tabs.toString());
        buffer.append("}\n");
    }
    return buffer.toString();
}

84
2017-09-02 16:15



Callcount ne yapılmalı? - Tom
Bunu çalıştırdığımda "AWT-EventQueue-0" iş parçacığı java.lang.StackOverflowError adlı özel durum var. - Tom
@Tom callCount sıfıra ayarlanmalıdır. Bu değer, her bir çıktı satırından kaç tane sekmenin çıkması gerektiğini belirlemek için kullanılır: her zaman dökümü bir "alt nesne" ye dökmek zorunda kaldığında, çıktı, üst öğede yuvalanmış olarak yazdırılır. Bu yöntem, bir diğerine sarıldığında faydalıdır. Düşünmek printDump(Object obj){ System.out.println(dump(obj, 0)); }. - fny
Java.lang.StackOverflowError, denetlenmemiş yineleme nedeniyle döngüsel referanslar durumunda oluşturulabilir: buffer.append (dump (value, callCount)) - Arnaud P
Kodunuzu Public Domain'e özel olarak serbest bırakabilir misiniz, lütfen? - stolsvik


Yansıma Kullanımları

Yansıma, Java sanal makinesinde çalışan uygulamaların çalışma zamanı davranışını inceleme veya değiştirme yeteneğini gerektiren programlar tarafından yaygın olarak kullanılır. Bu nispeten gelişmiş bir özelliktir ve yalnızca dilin temellerinin güçlü bir kavrayışına sahip geliştiriciler tarafından kullanılmalıdır. Bu uyarı akılda tutulduğunda, yansıma güçlü bir tekniktir ve uygulamaların, aksi halde imkansız olabilecek işlemleri gerçekleştirmesini sağlayabilir.

Genişletilebilirlik Özellikleri

Bir uygulama, tam nitelikli adlarını kullanarak genişletilebilirlik nesnelerinin örneklerini oluşturarak harici, kullanıcı tanımlı sınıflardan yararlanabilir. Sınıf Tarayıcılar ve Görsel Geliştirme Ortamları Bir sınıf tarayıcısının, sınıf üyelerini sıralayabilmesi gerekir. Görsel geliştirme ortamları, geliştiriciye doğru kodu yazarken yardımcı olmak için yansımada mevcut olan tip bilgisinin kullanılmasından yararlanabilir. Hata Ayıklayıcıları ve Test Araçları Hata ayıklayıcıların özel üyeleri sınıflarda inceleyebilmesi gerekir. Test kayışları, bir test paketinde yüksek düzeyde kod kapsamı sağlamak için bir sınıfta tanımlanan keşfedilebilir set API'lerini sistematik olarak çağırmak için yansımadan yararlanabilir.

Yansımadaki dezavantajlar

Yansıma güçlüdür, ancak ayrım yapılmamalıdır. Yansıma kullanılmadan bir işlem yapmak mümkün ise, bunu kullanmaktan kaçınmak tercih edilir. Yansıma yoluyla kodlara erişirken aşağıdaki endişeler akılda tutulmalıdır.

  • Performans yükü

Yansıma, dinamik olarak çözülen türleri içerdiğinden, bazı Java sanal makine optimizasyonları gerçekleştirilemez. Sonuç olarak, yansıtıcı işlemler, yansıtıcı olmayan benzerlerinden daha düşük performansa sahiptir ve performansa duyarlı uygulamalarda sıkça adlandırılan kod bölümlerinde önlenmelidir.

  • Güvenlik Kısıtlamaları

Yansıma, bir güvenlik yöneticisi altında çalışırken bulunmayabilecek bir çalışma zamanı izni gerektirir. Bu, bir Applet gibi kısıtlı bir güvenlik bağlamında çalışması gereken kod için önemli bir husustur.

  • İçsellerin Maruz Kalması

Yansıma, kodun, özel alanlara ve yöntemlere erişim gibi yansıtıcı olmayan kodda yasadışı olabilecek işlemleri gerçekleştirmesini sağladığı için, yansıma kullanımı, kodun işlevsiz hale gelmesine ve taşınabilirliği bozmasına neden olabilecek beklenmedik yan etkilere neden olabilir. Yansıtıcı kod, soyutlamaları bozar ve bu nedenle, platformun yükseltmeleriyle davranışları değiştirebilir.

kaynak: Yansıma API'sı


56
2017-10-17 11:59





Yansıma, bir uygulamanın veya çerçevenin henüz yazılmamış olabilecek kodlarla çalışmasına izin veren önemli bir mekanizmadır!

Örneğin, tipik web.xml dosyanızı alın. Bu iç içe servlet sınıfı elemanları içeren bir sunucu öğeleri listesi içerecektir. Servlet konteyneri, web.xml dosyasını işleyecek ve yansıma yoluyla yeni her bir sunucu sınıfının yeni bir örneğini oluşturacak.

Başka bir örnek XML Ayrıştırma için Java API'sı olacaktır (JAXP). Bir XML çözümleyici sağlayıcısının, yansıma yoluyla yeni örnekler oluşturmak için kullanılan iyi bilinen sistem özellikleri aracılığıyla 'takılı' olması durumunda.

Son olarak, en kapsamlı örnek bahar onun fasulyesini oluşturmak için yansımayı kullanır ve proxy'lerin yoğun kullanımı


30
2017-09-01 09:30





Her dil yansımayı desteklemez, ancak ilkeler genellikle onu destekleyen dillerde aynıdır.

Yansıma, programınızın yapısı üzerinde "yansıtma" yeteneğidir. Ya da daha somut. Sahip olduğunuz nesneler ve sınıflara bakmak ve uyguladıkları yöntemler, alanlar ve arayüzler hakkında programsal olarak geri bilgi almak. Ayrıca ek açıklamalar gibi şeylere de bakabilirsiniz.

Birçok durumda yararlıdır. Her yerde sınıfları dinamik olarak kodunuza takabilmek istiyorsunuz. Nesnenin çok yönlü haritacıları, nesneleri hangi nesneyi kullanacaklarını önceden bilmeden veri tabanlarından elde edebilmek için yansıma kullanırlar. Plug-in mimarileri, yansımanın yararlı olduğu başka bir yer. Kodları dinamik olarak yükleyebilmek ve bir eklenti olarak kullanmak için doğru arabirimi uygulayan türlerin olup olmadığını belirlemek bu durumlarda önemlidir.


27
2017-09-01 08:50



DB'de bulunan verilere dayanarak nesneleri başlatmam gerekiyor. Bunun hakkında söylediğinize inanıyorum. Örnek kod bana çok yardımcı olur. Şimdiden teşekkürler. - Atom


Yansıma, yeni nesnelerin oluşturulmasına, metotların çağrılmasına ve sınıf değişkenleri üzerinde, uygulama hakkında önceden bilgi sahibi olmadan, çalışma zamanında dinamik olarak alınmasına izin verir.

Class myObjectClass = MyObject.class;
Method[] method = myObjectClass.getMethods();

//Here the method takes a string parameter if there is no param, put null.
Method method = aClass.getMethod("method_name", String.class); 

Object returnValue = method.invoke(null, "parameter-value1");

Yukarıdaki örnekte, null parametresi, yöntemi çağırmak istediğiniz nesnedir. Eğer metot statik ise, null kaynağıdır. Yöntem statik değilse, o zaman çağırarak geçerli bir MyObject örneği null yerine sağlamanız gerekir.

Yansıma ayrıca bir sınıfa özel üye / yöntemlere erişmenizi sağlar:

public class A{

  private String str= null;

  public A(String str) {
  this.str= str;
  }
}

.

A obj= new A("Some value");

Field privateStringField = A.class.getDeclaredField("privateString");

//Turn off access check for this field
privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(obj);
System.out.println("fieldValue = " + fieldValue);
  • Sınıfların incelenmesi için (ayrıca iç gözlem olarak da bilinir) yansıma paketini içe aktarmanız gerekmez (java.lang.reflect). Sınıf meta verilerine şu yoldan erişilebilir: java.lang.Class.

Yansıma çok güçlü bir API'dır ancak çalışma zamanında tüm türleri çözdüğü için fazla kullanıldığında uygulamayı yavaşlatabilir.


26
2017-07-08 16:12



Bu cevap bölümlerinde bana en çok yardımcı olan gönderiydi, teşekkürler Nikhil - Enoy


Örnek :
Örneğin, uygulamanıza API Yöntemlerini kullanarak elde ettiğiniz bir nesneyi veren bir uzak uygulamayı alın. Şimdi nesneye bağlı olarak, bir çeşit hesaplamayı gerçekleştirmeniz gerekebilir.
Sağlayıcı, nesnenin 3 tür olduğunu garanti eder ve ne tür bir nesneye bağlı olarak hesaplama yapmamız gerekir.
Bu nedenle, her biri farklı bir mantık içeren 3 sınıfta uygulayabiliyoruz. Açıkçası, nesne bilgisi çalışma zamanında kullanılabilir. Bu nedenle, hesaplamayı gerçekleştirmek için statik olarak kodlayamazsınız. Bu nedenle, yansıma, sınıfın temelini oluşturmak için gereken sınıfın nesnesini başlatmak için kullanılır. Sağlayıcıdan alınan nesne.


18
2018-06-22 15:35



Benzer bir şeye ihtiyacım var. Bir örnek, yansıma kavramlarına yeni olduğum için bana çok yardımcı olacaktır .. - Atom
Kafam karıştı: kullanamaz mısın instanceof Çalışma zamanında nesne türünü belirlemek için? - ndm13


Java Yansıma oldukça güçlü ve çok kullanışlı olabilir. Java Reflection mümkün kılar çalışma zamanında sınıfları, arayüzleri, alanları ve yöntemleri incelemek,derleme zamanında sınıfların, yöntemlerin vb. isimlerini bilmeden. Ayrıca mümkündür yeni nesneler oluşturmak, yöntemleri çağırmak ve yansıma kullanarak alan değerlerini almak / ayarlamak.

Yansımayı kullanarak neye benzediğini göstermek için hızlı bir Java Yansıtma örneği:

Method[] methods = MyObject.class.getMethods();

    for(Method method : methods){
        System.out.println("method = " + method.getName());
    }

Bu örnek, Class nesnesini MyObject adlı sınıftan alır. Sınıf nesnesini kullanarak örnek, bu sınıftaki yöntemlerin bir listesini alır, yöntemleri yineler ve adlarını yazdırır.

Bütün bu çalışmaların tam olarak burada açıklandığı

Düzenle: Yaklaşık 1 yıl sonra bu cevabı düzenlerken, Yansıma hakkında daha fazla kullanımım var.

  • İlkbahar, fasulye konfigürasyonunu şöyle kullanır:


<bean id="someID" class="com.example.Foo">
    <property name="someField" value="someValue" />
</bean>

Bahar içeriği bu <bean> öğesini işlediğinde, Class.forName (String), bu sınıfı başlatmak için "com.example.Foo" argümanıyla birlikte kullanılacaktır.

Daha sonra <property> öğesi için uygun ayarlayıcıyı almak ve değerini belirtilen değere ayarlamak için yansımayı tekrar kullanır.

  • Junit, özellikle Özel / Korumalı yöntemleri sınamak için Yansıma'yı kullanır.

Özel yöntemler için

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

Özel alanlar için

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

17
2017-09-08 09:40





Benim anlayışına göre:

Yansıma, programcının programdaki varlıklara dinamik olarak erişmesini sağlar. yani, bir programın bir sınıf veya yöntemlerinden habersiz olması durumunda bir uygulamayı kodlarken, bu sınıfı, yansıma kullanarak (çalışma zamanında) dinamik olarak kullanabilir.

Bir sınıf adının sık sık değiştiği senaryolarda sıkça kullanılır. Böyle bir durum ortaya çıkarsa, programcının yeniden yazması ve sınıfın adını tekrar tekrar yazması karmaşıktır.

Bunun yerine, yansıma kullanarak, muhtemelen değişen bir sınıf adı hakkında endişelenmeniz gerekir.


12
2018-02-06 05:37





yansıma için basit bir örnek. Bir Satranç Oyununda, kullanıcı tarafından çalışma zamanında ne taşınacağını bilmiyorsunuz. Yansıma, çalışma zamanında uygulanan yöntemleri çağırmak için kullanılabilir.

public class Test {

    public void firstMoveChoice(){
        System.out.println("First Move");
    } 
    public void secondMOveChoice(){
        System.out.println("Second Move");
    }
    public void thirdMoveChoice(){
        System.out.println("Third Move");
    }

    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 
        Test test = new Test();
        Method[] method = test.getClass().getMethods();
        //firstMoveChoice
        method[0].invoke(test, null);
        //secondMoveChoice
        method[1].invoke(test, null);
        //thirdMoveChoice
        method[2].invoke(test, null);
    }

}

12
2017-11-06 04:42