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


2124

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

Özellikle Java ile ilgileniyorum, ancak ilkelerin herhangi bir dilde aynı olduğunu varsayıyorum.


9
Benim için bu, çalışma zamanında sınıf adları almanın ve o sınıfın nesnelerini oluşturmanın bir yoludur.
Nabin

64
çünkü bu popüler bir soru olduğunu belirtmek isterim ki, yansıma (ek açıklama olmadan) bir sorunu çözerken gideceğiniz en son araç olmalıdır. Kullanıyorum ve seviyorum, ancak Java'nın statik yazımının tüm avantajlarını iptal ediyor. İhtiyacınız varsa, mümkün olduğunca küçük bir alana ayırın (Bir yöntem veya bir sınıf). Testlerde üretim kodundan daha kabul edilebilir. Ek açıklamalarda sorun yoktur - Ana nokta, sınıf veya yöntem adlarını "Dizeler" olarak belirtmektir.
Bill K


4
@ BillK'nın yorumuna ek olarak: Yansıma çok güçlü, buna sihir derim. Büyük güç büyük sorumluluk getirir. Sadece ne yaptığınızı biliyorsanız kullanın.
MC İmparatoru

Manifold kullanarak yansıma ile ilgili birçok tuzaktan kaçınabilirsiniz @Jailbreak. Özel alanlara, yöntemlere vb. Doğrudan, güvenli bir erişim sağlar. Java derleyicisinin kodunuzu güvenli bir şekilde doğrulamasına ve Manifold'un sizin için temel yansıma erişimini oluşturmasına izin verin. Daha fazla bilgi edinin: manifold.systems/docs.html#type-safe-reflection
Scott

Yanıtlar:


1716

Yansıma yansıması, aynı sistemdeki (veya kendisindeki) diğer kodu inceleyebilen kodu tanımlamak için kullanılır.

Örneğin, Java'da bilinmeyen türde bir nesneniz olduğunu ve varsa 'doSomething' yöntemini çağırmak istediğinizi varsayalım. Java'nın statik yazım sistemi, nesne bilinen bir arabirime uymadıkça bunu destekleyecek şekilde tasarlanmamıştır, ancak yansıma kullanarak kodunuz nesneye bakabilir ve 'doSomething' adlı bir yöntemi olup olmadığını öğrenebilir ve sonra istemek.

Yani, Java'da bunun bir kod örneğini vermek için (söz konusu nesnenin foo olduğunu hayal edin):

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 ek açıklamasıyla etiketlenmiş yöntemler için sınıflarınıza bakmak için yansıma kullanır ve ardından birim sınamasını çalıştırırken bunları arar.

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

Ve son olarak, evet, kavramlar yansımayı destekleyen (C # gibi) statik olarak yazılmış diğer dillerde oldukça benzerdir. 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 verir, yoksa çalışma zamanında başarısız olur), ancak ikinci veya işaretli yöntemleri arama durumu belirli bir şekilde çalışmak hala yaygındır.

Bir yorumdan güncelleme:

Sistemdeki kodu inceleme ve nesne türlerini görme yeteneği yansıma değil, Tip İçgözlemdir. Bu durumda yansıma, içgözlemi kullanarak çalışma zamanında değişiklik yapma yeteneğidir. Bazı diller içgözlemi desteklediğinden, ancak yansımayı desteklemediğinden, ayrım burada gereklidir. Böyle bir örnek C ++


32
u bu satırda null parametrenin önemini açıklayabilir misiniz Yöntem yöntemi = foo.getClass (). getMethod ("doSomething", null);
Krsna Chaitanya

54
Null değeri, foo yöntemine iletilen parametre olmadığını gösterir. Ayrıntılar için bkz. Docs.oracle.com/javase/6/docs/api/java/lang/reflect/… , java.lang.Object ...).
Matt Sheppard

791
Sadece bu kadar çok oyu var çünkü temizlemek için. Sistemdeki kodu inceleme ve nesne türlerini görme yeteneği yansıma değildir, daha ziyade Tür İçgözlemdir. Bu durumda yansıma, içgözlemi kullanarak çalışma zamanında değişiklik yapma yeteneğidir. Bazı diller içgözlemi desteklediğinden, ancak yansımayı desteklemediğinden, ayrım burada gereklidir. Böyle bir örnek C ++.
bigtunacan

39
Yansımayı seviyorum ama kod üzerinde kontrolünüz varsa, o zaman bu cevapta belirtildiği gibi yansımayı kullanmak unnessary ve bu nedenle bir kötüye kullanımdır - Type Introspection (instanceof) ve güçlü türleri kullanmalısınız. Bir şey yapmanın yansımasından başka bir yolu varsa, böyle yapılması gerekir. Yansıma, ciddi bir acıya neden olur, çünkü statik olarak yazılan bir dili kullanmanın tüm avantajlarını kaybedersiniz. İhtiyacınız varsa, ancak buna rağmen Spring gibi önceden paketlenmiş bir çözümü veya gerekli yansımayı tamamen kapsülleyen bir şeyi düşünürüm - IE: Başkasının baş ağrısına sahip olmasına izin verin.
Bill K

6
@bigtunacan Bu bilgiyi nereden aldınız? Oracle'ın resmi Java belgelerinde kullanılan ve yalnızca çalışma zamanında değişiklik yapma yeteneğini değil, aynı zamanda bir nesnenin türünü de görme yeteneğini tanımlamak için kullanılan "yansıma" terimini görüyorum. Çoğu sözde "tipi introspection" ilişkili sınıfları bahsetmeye bile gerek yok (örn: Method, Constructor, Modifier, Field, Member, temelde görünüşte bütün hariç Class) içindedir java.lang.*reflect*paketin. Belki de "yansıma" kavramı kapsamlı olarak hem "tip içgözlemi" hem de çalışma anında modifikasyonu içerir?
RestInPeace

246

Yansıma , bir dilin çalışma zamanında sınıfları, yöntemleri, nitelikleri vb. İnceleme ve dinamik olarak arama yeteneğidir.

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

Yansıma önemlidir, çünkü her şeyi derleme zamanında "bilmek" zorunda olmayan programlar yazmanıza izin verir, böylece daha dinamik hale getirir, çünkü çalışma zamanında birbirine bağlanabilirler. Kod, bilinen arabirimlere karşı yazılabilir, ancak kullanılacak gerçek sınıflar yapılandırma dosyalarından yansıma kullanılarak başlatılabilir.

Birçok modern çerçeve bu nedenle yansımayı yoğun bir şekilde kullanmaktadır. Diğer birçok modern dil de yansımayı kullanır ve kodlama dillerinde (Python gibi), bu dillerin genel programlama modeli içinde daha doğal hissettiklerinden daha sıkı bir şekilde entegre edilirler.


2
Başka bir deyişle, nitelikli adından bir örnek oluşturabilirsiniz ve derleyici bundan şikayet etmez (çünkü sınıf adı için sadece bir String kullandığınızı söyleyin). Sonra, çalışma zamanında, bu sınıf yoksa bir istisna alırsınız. Bu durumda derleyiciyi atladınız. Bunun için bana belirli bir kullanım durumu verir misiniz? Sadece ne zaman seçeceğimi hayal edemiyorum.
Fernando Gabrieli

3
@FernandoGabrieli yansıma ile çalışma zamanı hataları oluşturmanın kolay olduğu doğru olsa da, çalışma zamanı istisnalarını riske atmadan yansıma kullanmak da mükemmel bir şekilde mümkündür. Cevabım ima gibi, yansıma yaygın kullanımı açıkça kütüphaneler veya çerçeveler içindir olamaz onlar uygulamasından ayrı derlenmiş olduğundan, derleme zamanında uygulamanın yapısını biliyoruz. "Kural gereği kod" kullanan herhangi bir kitaplığın yansıma kullanması muhtemeldir, ancak sihirli dizeler kullanması gerekmez.
Liedman

C++Çalışma zamanı türü bilgisine sahip. RTTI
Ayxan

114

En sevdiğim yansıma kullanımlarından biri aşağıdaki Java dökümü yöntemidir. Herhangi bir nesneyi 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();
}

8
Çağrı sayısı neye ayarlanmalıdır?
Tom

8
Bu çalıştırdığımda "AWT-EventQueue-0" java.lang.StackOverflowError iş parçacığında bir özel durum var.
Tom

3
@Tom callCountsıfıra ayarlanmalıdır. Bu değer, her bir çıktı satırından önce kaç sekme olacağını belirlemek için kullanılır: dökümün bir "alt nesne" yi her boşaltması gerektiğinde, çıktı üst öğeye yuvalanmış olarak yazdırılır. Bu yöntem bir başkasına sarıldığında faydalıdır. Düşünün printDump(Object obj){ System.out.println(dump(obj, 0)); }.
fny

1
Java.lang.StackOverflowError, denetlenmeyen özyineleme nedeniyle döngüsel başvurularda oluşturulabilir: buffer.append (dump (value, callCount))
Arnaud P

4
Kodunuzu özellikle Public Domain'e bırakabilir misiniz, lütfen?
stolsvik

84

Yansıma Kullanımı

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 temellerini güçlü bir şekilde kavrayan geliştiriciler tarafından kullanılmalıdır. Bu uyarı dikkate alındığında, yansıma güçlü bir tekniktir ve uygulamaların aksi takdirde imkansız olabilecek işlemleri gerçekleştirmesini sağlayabilir.

Genişletilebilirlik Özellikleri

Bir uygulama, tam nitelenmiş adlarını kullanarak genişletilebilirlik nesneleri örnekleri oluşturarak harici, kullanıcı tanımlı sınıflardan yararlanabilir. Sınıf Tarayıcıları ve Görsel Geliştirme Ortamları Sınıf tarayıcısı, sınıf üyelerini numaralandırabilmelidir. Görsel geliştirme ortamları, geliştiricinin doğru kod yazmasına yardımcı olmak için tür bilgisini yansımada kullanmaktan yararlanabilir. Hata Ayıklayıcılar ve Test Araçları Hata ayıklayıcıların sınıflardaki özel üyeleri inceleyebilmeleri gerekir. Test kabloları, bir test paketinde yüksek düzeyde kod kapsamı sağlamak için, bir sınıfta tanımlanan keşfedilebilir bir set API'leri sistematik olarak çağırmak için yansımayı kullanabilir.

Yansıma Dezavantajları

Yansıma güçlüdür, ancak gelişigüzel kullanılmamalıdır. Bir işlemi yansıma kullanmadan gerçekleştirmek mümkünse, kullanmaktan kaçınmak tercih edilir. Yansıtma yoluyla koda erişirken aşağıdaki endişeler akılda tutulmalıdır.

  • Performans Genel Yükü

Yansıma, dinamik olarak çözümlenen türleri içerdiğinden, bazı Java sanal makine optimizasyonları gerçekleştirilemez. Sonuç olarak, yansıtıcı işlemler yansıtıcı olmayan muadillerine göre daha yavaş performansa sahiptir ve performansa duyarlı uygulamalarda sıkça çağrılan kod bölümlerinden kaçınılmalıdır.

  • Güvenlik Kısıtlamaları

Yansıma, bir güvenlik yöneticisi altında çalışırken var olmayabilecek 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.

  • İçsel Pozlama

Yansıma, kodun özel alanlara ve yöntemlere erişim gibi yansıtıcı olmayan kodda yasa dışı olacak işlemleri gerçekleştirmesine izin verdiğinden, yansıma kullanımı, kodun işlevsiz hale gelmesine ve taşınabilirliği yok edebilecek beklenmedik yan etkilere neden olabilir. Yansıtıcı kod soyutlamaları bozar ve bu nedenle platformun yükseltilmesiyle davranışı değiştirebilir.

Kaynak: Yansıma API'sı


44

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 sunucu uygulaması sınıfı öğeler içeren sunucu uygulaması öğelerinin bir listesini içerecektir. Sunucu uygulaması kapsayıcısı web.xml dosyasını işler ve yansıma yoluyla her sunucu uygulaması sınıfının yeni bir örneğini oluşturur.

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

Ve son olarak, en kapsamlı örneği Bahar onun fasulye oluşturmak için yansıma kullanır ve vekiller kendi ağır kullanımı için hangi


36

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

Yansıma, programınızın yapısına "yansıtma" yeteneğidir. Veya daha somut. Sahip olduğunuz nesnelere ve sınıflara bakmak ve uyguladıkları yöntemler, alanlar ve arabirimler hakkında programlı olarak geri bilgi almak. Ek açıklamalar gibi şeylere de bakabilirsiniz.

Birçok durumda faydalıdır. Sınıfları dinamik olarak kodunuza eklemek istediğiniz her yerde. Lot'un nesne ilişkisel eşleyicileri, hangi nesneleri kullanacaklarını önceden bilmeden nesneleri veritabanlarından somutlaştırmak için yansımayı kullanır. Plug-in mimarileri, yansımanın faydalı olduğu başka bir yerdir. Dinamik olarak kod yükleyebilmek ve orada eklenti olarak kullanmak için doğru arayüzü uygulayan türler olup olmadığını belirlemek bu durumlarda önemlidir.


DB mevcut verilere dayalı nesneleri somutlaştırmak gerekiyor. Bunun hakkında söylediklerinize inanıyorum. Örnek kod bana çok yardımcı olacaktır. Şimdiden teşekkürler.
Atom

34

Yansıma, yeni nesnelerin somutlaştırılmasına, yöntemlerin çağrılmasına ve sınıf değişkenleri üzerinde uygulama hakkında önceden bilgisi olmadan dinamik olarak çalışma / alma işlemlerine 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. Yöntem statikse null değerini sağlarsınız. Yöntem statik değilse, çağrılırken null yerine geçerli bir MyObject örneği sağlamanız gerekir.

Yansıma ayrıca bir sınıfın özel üyesine / yöntemlerine 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 (introspection olarak da bilinir) yansıma paketini ( java.lang.reflect) içe aktarmanız gerekmez . Sınıf meta verilerine erişilebilir java.lang.Class.

Yansıma çok güçlü bir API'dir, ancak fazla kullanılırsa uygulamayı yavaşlatabilir, çünkü çalışma zamanında tüm türleri çözer.


21

Java Yansıması oldukça güçlüdür ve çok yararlı olabilir. Java Yansıma , derleme sırasında sınıfların, yöntemlerin vb. Adlarını bilmeden, çalışma zamanında sınıfları, arabirimleri, alanları ve yöntemleri denetlemeyi mümkün kılar . Yansıma kullanarak yeni nesneleri başlatmak, yöntemleri çağırmak ve alan değerlerini almak / ayarlamak da mümkündür .

Yansımayı kullanmanın neye benzediğini gösteren 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, o sınıftaki yöntemlerin bir listesini alır, yöntemleri yineler ve adlarını yazdırır.

Tüm bunların nasıl çalıştığı burada açıklanmaktadır

Edit : Neredeyse 1 yıl sonra ben yansıma hakkında okurken Yansıma daha az kullanır var gibi bu cevabı düzenliyorum.

  • Yay, aşağıdaki gibi fasulye yapılandırmasını kullanır:


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

Spring bağlamı bu <bean> öğesini işlediğinde, Class.forName (String) öğesini, bu Sınıfı başlatmak için "com.example.Foo" bağımsız değişkeniyle kullanır.

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

  • Junit, Reflection'ı özellikle Özel / Korumalı yöntemleri test etmek için 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);

21

Misal:

Örneğin, uygulamanıza API Yöntemlerini kullanarak elde ettiğiniz bir nesneyi veren uzak bir uygulamayı ele alalım. Şimdi nesneyi temel alarak bir tür hesaplama yapmanız gerekebilir.

Sağlayıcı, nesnenin 3 tür olabileceğini garanti eder ve hangi tür nesneye bağlı olarak hesaplama yapmamız gerekir.

Bu nedenle, her biri farklı bir mantık içeren 3 sınıfta uygulayabiliriz. sağlayıcıdan alınan nesne.


Benzer bir şeye ihtiyacım var .. Bir örnek bana yansıma kavramlarında yeni olduğum için çok yardımcı olur ..
Atom

2
Kafam karıştı: instanceofçalışma zamanında nesne türünü belirlemek için kullanamaz mısınız?
ndm13

19

Yansıma için basit bir örnek. Bir satranç oyununda, kullanıcı tarafından çalışma zamanında nelerin taşınacağını bilmiyorsunuz. yansıma, çalışma zamanında uygulanmış olan 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);
    }

}

18

Yansıma , çalışma zamanında yöntemlerin, sınıfların, arabirimlerin davranışını incelemek veya değiştirmek için kullanılan bir API'dir .

  1. Düşünme için gerekli sınıflar altında verilmiştir java.lang.reflect package.
  2. Yansıma bize bir nesnenin ait olduğu sınıf ve bu sınıfın nesne kullanılarak yürütülebilecek yöntemleri hakkında bilgi verir.
  3. Yansıma yoluyla, onlarla kullanılan erişim belirtecinden bağımsız olarak çalışma zamanında yöntemleri çağırabiliriz.

java.langVe java.lang.reflectpaketler java yansıması için sınıfları sağlar.

Yansıma hakkında bilgi almak için kullanılabilir -

  1. SınıfgetClass() yöntemi nesnesinin ait olduğu sınıfın adını elde etmek için kullanılır.

  2. YapıcılargetConstructors() yöntem nesnesinin ait olduğu sınıfın genel kurucular elde etmek için kullanılır.

  3. YöntemgetMethods() yöntem, nesnelerin ait olduğu sınıfın genel yöntemleri elde etmek için kullanılır.

Reflection API esas olarak kullanılır:

IDE (Entegre Geliştirme Ortamı) örneğin Eclipse, MyEclipse, NetBeans vb.
Hata Ayıklayıcı ve Test Araçları vb.

Yansıma Kullanmanın Avantajları:

Genişletilebilirlik Özellikleri: Bir uygulama, tam nitelikli adlarını kullanarak genişletilebilirlik nesneleri örnekleri oluşturarak harici, kullanıcı tanımlı sınıflardan yararlanabilir.

Hata ayıklama ve test araçları: Hata ayıklayıcılar, sınıftaki özel üyeleri incelemek için yansıtma özelliğini kullanır.

Dezavantajları:

Performans Yükü: Yansıtıcı işlemler yansıtıcı olmayan karşılıklarından daha yavaş performansa sahiptir ve performansa duyarlı uygulamalarda sıkça çağrılan kod bölümlerinden kaçınılmalıdır.

Dahili İçindekilere Maruz Kalma: Yansıtıcı kod soyutlamaları bozar ve bu nedenle platformun yükseltilmesiyle davranışı değiştirebilir.

Referans: Java Yansıma javarevisited.blogspot.in


4
Ben de " Yeniden düzenleme tatili " dezavantajları eklemek istiyorum . Benim için mümkün olduğunca düşünmekten kaçınmanın ana nedeni budur.
SantiBailors

Bu yüzden (örneğin), sahip olduğumuz sınıfları incelememize izin veriyor (bunların örnekleri olsun ya da olmasın), doğru mu? Bununla, yöntemlerini veya kurucularını alın ve bunları yeni örnekler oluşturmak / onları çağırmak için kullanın. Davranış zaten oradaysa ancak farklı bir kodla varsa neden "program davranışını değiştirme" diyoruz? Neden buna "yansıma" deniyor? Teşekkürler
Fernando Gabrieli

15

Anladığım kadarıyla:

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

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

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


15

Yansıma, programınızın çalışma zamanı bilgilerine erişmenize ve programın davranışını değiştirmenize (bazı sınırlamalarla) izin veren bir dizi işlevdir.

Programınızın meta bilgilerine bağlı olarak çalışma zamanı davranışını değiştirmenize izin verdiği için yararlıdır, yani bir işlevin dönüş türünü kontrol edebilir ve durumu işleme şeklinizi değiştirebilirsiniz.

Örneğin C # 'da bir derleme (bir .dll) çalışma zamanında yükleyebilir, sınıflar arasında gezinebilir ve bulduğunuza göre eylemler gerçekleştirebilirsiniz. Ayrıca çalışma zamanında bir sınıf örneği oluşturmanıza, yöntemini çağırmanıza vb. İzin verir.

Nerede yararlı olabilir? Her zaman değil, somut durumlar için yararlıdır. Örneğin, günlüğe kaydetme amacıyla sınıfın adını almak, bir yapılandırma dosyasında belirtilenlere göre olaylar için dinamik olarak işleyiciler oluşturmak için kullanabilirsiniz ...


11

Listelenen her şeye biraz puan eklemek istiyorum.

Reflection API ile toString()herhangi bir nesne için evrensel yöntem yazabilirsiniz .

Hata ayıklamada kullanışlıdır.

İşte bazı örnek:

class ObjectAnalyzer {

   private ArrayList<Object> visited = new ArrayList<Object>();

   /**
    * Converts an object to a string representation that lists all fields.
    * @param obj an object
    * @return a string with the object's class name and all field names and
    * values
    */
   public String toString(Object obj) {
      if (obj == null) return "null";
      if (visited.contains(obj)) return "...";
      visited.add(obj);
      Class cl = obj.getClass();
      if (cl == String.class) return (String) obj;
      if (cl.isArray()) {
         String r = cl.getComponentType() + "[]{";
         for (int i = 0; i < Array.getLength(obj); i++) {
            if (i > 0) r += ",";
            Object val = Array.get(obj, i);
            if (cl.getComponentType().isPrimitive()) r += val;
            else r += toString(val);
         }
         return r + "}";
      }

      String r = cl.getName();
      // inspect the fields of this class and all superclasses
      do {
         r += "[";
         Field[] fields = cl.getDeclaredFields();
         AccessibleObject.setAccessible(fields, true);
         // get the names and values of all fields
         for (Field f : fields) {
            if (!Modifier.isStatic(f.getModifiers())) {
               if (!r.endsWith("[")) r += ",";
               r += f.getName() + "=";
               try {
                  Class t = f.getType();
                  Object val = f.get(obj);
                  if (t.isPrimitive()) r += val;
                  else r += toString(val);
               } catch (Exception e) {
                  e.printStackTrace();
               }
            }
         }
         r += "]";
         cl = cl.getSuperclass();
      } while (cl != null);

      return r;
   }    
}

11

Yansıma, nesnenin görünüşlerini görmesine izin vermektir. Bu argümanın yansıma ile ilgisi yoktur. Aslında, bu "kendini tanımlama" yeteneğidir.

Yansımanın kendisi, Java ve C # gibi kendini tanıma ve kendini algılama yeteneğinden yoksun olan diller için bir kelimedir. Kendini tanıma yeteneğine sahip olmadıkları için, nasıl göründüğünü gözlemlemek istediğimizde, nasıl göründüğünü yansıtacak başka bir şeye sahip olmalıyız. Ruby ve Python gibi mükemmel dinamik diller, diğer bireylerin yardımı olmadan kendi yansımalarını algılayabilir. Java nesnesinin yansıma sınıfının bir nesnesi olan bir ayna olmadan nasıl göründüğünü algılayamadığını söyleyebiliriz, ancak Python'daki bir nesne onu bir ayna olmadan algılayabilir. Bu yüzden Java'da düşünmeye ihtiyacımız var.


type (), isinstance (), callable (), dir () ve getattr (). .... bunlar
pitonik

9

Java dokümantasyon sayfasından

java.lang.reflectpaketi, sınıflar ve nesneler hakkında yansıtıcı bilgiler elde etmek için sınıflar ve arabirimler sağlar. Yansıma, yüklenen sınıfların alanları, yöntemleri ve kurucuları hakkındaki bilgilere ve güvenlik kısıtlamaları dahilinde temel meslektaşları üzerinde çalışmak için yansıyan alanların, yöntemlerin ve kurucuların kullanımına ilişkin bilgilere programlı erişim sağlar.

AccessibleObjectgerekli ReflectPermissionolduğunda erişim kontrollerinin bastırılmasına izin verir .

İle birlikte bu pakette Sınıflar, java.lang.Classböyle debugger'lar, tercümanlar, nesne müfettişleri, sınıf tarayıcılar ve gibi hizmetleri gibi uygulamalar barındırmak Object Serializationve JavaBeansbir hedef nesnenin kamu üyelerine ya o ihtiyacı erişimi (kendi çalışma zamanı sınıfına göre) veya üyeleri tarafından ilan belirli bir sınıf

Aşağıdaki işlevleri içerir.

  1. Sınıf nesneleri elde etme,
  2. Bir sınıfın özelliklerini inceleme (alanlar, yöntemler, yapıcılar),
  3. Alan değerlerini ayarlama ve alma,
  4. Çağırma yöntemleri,
  5. Nesnelerin yeni örneklerini oluşturma.

Sınıfa maruz kalan yöntemler için bu dokümantasyon bağlantısına bir göz atın Class.

Bu makaleden (Sosnoski Software Solutions, Inc. Başkanı Dennis Sosnoski tarafından) ve bu makaleden (güvenlik araştırmaları pdf):

Reflection kullanımından çok önemli dezavantajlar görüyorum

Yansıtma Kullanıcısı:

  1. Program bileşenlerini dinamik olarak bağlamak için çok yönlü bir yol sağlar
  2. Nesnelerle çok genel yollarla çalışan kütüphaneler oluşturmak için kullanışlıdır

Yansıma Dezavantajları:

  1. Alan ve yöntem erişimi için kullanıldığında yansıma doğrudan koddan çok daha yavaştır.
  2. Kodunuzun içinde neler olup bittiğini gizleyebilir
  3. Kaynak kodunu atlayarak bakım sorunları yaratabilir
  4. Yansıma kodu da karşılık gelen doğrudan koddan daha karmaşıktır
  5. Veri erişim koruması ve tür güvenliği gibi önemli Java güvenlik kısıtlamalarının ihlaline izin verir

Genel istismarlar:

  1. Kısıtlı sınıfların yüklenmesi,
  2. Kısıtlı bir sınıfın yapıcılarına, yöntemlerine veya alanlarına referans alma,
  3. Yeni nesne örnekleri oluşturma, yöntem çağırma, kısıtlı bir sınıfın alan değerlerini alma veya ayarlama.

Yansıma özelliğinin kötüye kullanılmasıyla ilgili bu SE sorusuna bir göz atın:

Java'da özel bir alanı nasıl okurum?

Özet:

Bir sistem kodundan yürütülen işlevlerinin güvenli olmayan şekilde kullanılması, Java güvenlik modunun l tehlikeye girmesine de yol açabilir . Bu özelliği çok az kullanın


Yansımanın performans sorunlarından kaçınmanın bir yolu, bazı durumlarda Woozlestatik olan bir RegisterAsWoozleHelper()yöntemi olduğunu görmek için bir sınıfın başlangıçta diğer sınıfları incelemesi ve buldukları tüm bu yöntemleri Woozlekendi kendilerine anlatmak için kullanabilecekleri bir geri arama ile çağırmaktır. örneğin verilerin serileştirilmesini kaldırırken Yansıma özelliğini kullanmanız gerekir.
supercat

9

Adından da anlaşılacağı gibi, çalışma zamanında dinamik olarak örnek oluşturma yöntemini çağırmak için özellik sağlama dışında, örneğin sınıf yöntemi, vb.

Aslında kodu bilmeden hizmetleri çağırmak için birçok çerçeve ve ahşap altındaki uygulama tarafından kullanılır.


7

Yansıma size daha genel kod yazma yeteneği verir. Çalışma zamanında bir nesne oluşturmanıza ve çalışma zamanında yöntemini çağırmanıza olanak tanır. Bu nedenle program yüksek oranda parametrelendirilebilir. Ayrıca, dış dünyaya maruz kalan değişkenlerini ve yöntemini tespit etmek için nesne ve sınıfın iç gözlemine izin verir.


6

Reflectionbirçok kullanım alanı vardır . Daha aşina olduğum şey, anında kod oluşturabilmektir.

IE: dinamik sınıflar, fonksiyonlar, kurucular - herhangi bir veriye dayanır (xml / array / sql results / hardcoded / etc ..)


1
Bir SQL sonucundan veya XML dosyasından vb. Oluşturulmuş kodun sadece sıra dışı bir örneğini verdiyseniz, bu cevap çok daha iyi olurdu.
ThisClark

Sorun değil. Dinamik olarak bir veritabanından alınan XML tabanlı arayüzü üreten bir windows uygulamasında yansıma kullandım.
Ess Kay

Temel olarak, oluşturduğum ve kullanıcıya bir rapor gösteren bir sınıf var. Bu raporda Date (itibaren) kimliği veya başka herhangi bir parametre vardır. Bu bilgi xml'de saklanır. İlk önce bir rapor seçimimiz var. Seçilen rapora göre, form xml'yi alır. Xml alındıktan sonra, yansıyan türlere dayalı alanlara sahip bir sınıf oluşturmak için yansıma kullanır. Farklı bir rapora geçtiğinizde, seçenek listesi temizlenir ve xml'ye göre yeni alanlar oluşturulur. Yani aslında yansımaya dayalı dinamik bir form. Ayrıca başka şekillerde de kullandım ama bu yardımcı olabilecek yeterli bir umut olmalı
Ess Kay

3

Bu soruyu örnek olarak cevaplamak istiyorum. Her şeyden önce Hibernateproje , çalışan uygulama ile kalıcılık deposu arasındaki uçurumu kapatmak için ifadeler Reflection APIoluşturmak CRUDiçin kullanır . Alanda işler değiştiğinde, Hibernatebunları veri deposuna devam ettirmek için tam olarak bilmesi gerekir.

Alternatif olarak çalışır Lombok Project. Yalnızca derleme zamanında kod enjekte eder ve kodun etki alanı sınıflarınıza eklenmesine neden olur. (Bence alıcılar ve ayarlayıcılar için sorun yok)

Hibernatereflectionbir uygulama için oluşturma işlemi üzerinde çok az etkisi olduğundan seçti .

Ve Java 7'den, bizim gibi MethodHandlesçalışıyor Reflection API. Projelerde, kaydedicilerle çalışmak için bir sonraki kodu kopyalayıp yapıştırıyoruz:

Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName());

Çünkü bu durumda yazım hatası yapmak zordur.


3

Örnekle açıklamayı en iyi bulduğum ve cevapların hiçbiri bunu yapmıyor gibi görünüyor ...

Yansımaları kullanmanın pratik bir örneği, Java ile yazılmış bir Java Dil Sunucusu veya PHP, vb. İle yazılmış bir PHP Dil Sunucusu olabilir. Dil Sunucusu, IDE'nize otomatik tamamlama, tanımlamaya atlama, bağlam yardımı, ipucu türleri ve daha fazlası gibi yetenekler verir. Dil Sunucusu'nu yazarken olası tüm eşleşmeleri göstermek için tüm etiket adlarının (otomatik olarak tamamlanabilen kelimeler) olması için, doc blokları ve özel üyeler de dahil olmak üzere sınıfla ilgili her şeyi incelemesi gerekir. Bunun için söz konusu sınıfın bir yansımasına ihtiyacı var.

Farklı bir örnek, özel bir yöntemin birim testi olabilir. Bunu yapmanın bir yolu, bir yansıma oluşturmak ve testin kurulum aşamasında yöntemin kapsamını herkese açık olarak değiştirmektir. Tabii ki, özel yöntemlerin doğrudan test edilmemesi gerektiğini savunabiliriz ama mesele bu değil.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.