A reflexió ( reflexió ; az introspekció holonimája , angolul reflexió ) egy olyan folyamat, amelynek során a program nyomon követheti és módosíthatja saját struktúráját és viselkedését futás közben. A reflexió mögött meghúzódó programozási paradigma a metaprogramozás egyik formája [1] , és reflektív programozásnak hívják .
A programutasítások (kód) végrehajtása során a számítógépek adatokat dolgoznak fel, ami annak megváltozásához vezet, míg a számítógépek nem változtatják meg a kódot. A legtöbb modern számítógép-architektúrában azonban a kódot adatként tárolják, és egyes programozási nyelvek képesek a natív kódot adatként kezelni, ami magában a kódban változásokhoz vezet a végrehajtás során. Az ilyen önmódosító programok többnyire virtuális gépeket használó magas szintű programozási nyelvekkel készülnek (pl. Smalltalk , szkriptnyelvek ). Kisebb mértékben a reflexiót használják deklarált vagy statikus típusú nyelvekben (pl . C , ML , Haskell , F# ).
A reflexió fogalmát a programozási nyelvekben Brian Cantwell Smith vezette be 1982 -es doktori disszertációjában [ 2] [3] , valamint a meta - circular evaluator koncepcióját a 3-Lisp összetevőjeként .
A reflektív-orientált programozás vagy a reflektív programozás az objektum-orientált programozási paradigma funkcionális kiterjesztése . A reflexió-orientált programozás magában foglalja az önellenőrzést, az önmódosítást és az önklónozást. A reflexió-orientált paradigma fő előnye azonban a program dinamikus módosításában rejlik, amely a program futása közben definiálható és végrehajtható. Egyes elengedhetetlen megközelítések, mint például a procedurális és objektumorientált programozási paradigmák, azt jelzik, hogy az adatfeldolgozási műveletek előre meghatározott sorrendje létezik. A reflektív-orientált programozási paradigma azonban lehetőséget ad a programutasítások dinamikus módosítására futás közben, és módosított formában történő meghívására. Vagyis maga a szoftverarchitektúra határozza meg, hogy az adatok, szolgáltatások és konkrét műveletek alapján pontosan mit lehet működés közben elvégezni.
A tükrözés segítségével a program végrehajtása során megfigyelhető és módosítható. A program reflektív komponense megfigyelheti egy bizonyos kódrészlet végrehajtását, és megváltoztathatja önmagát a kívánt cél elérése érdekében. A módosítás a program végrehajtása során a kód dinamikus megváltoztatásával történik.
A tükrözés segítségével dinamikusan adaptálható a program a különböző helyzetekhez. Vegyünk például egy olyan programot, amely két különböző osztályt használ, Xés Yhasonló műveleteket hajt végre. A programkód tükröződése nélkül az osztálymetódusok kifejezetten meghívásra kerülnek X. YHa a programot a reflexió-orientált programozási paradigmával tervezték, a kód bizonyos részei nem tartalmaznak explicit hívásokat az osztálymetódusokra Xés Y; a program ezt a szakaszt kétszer hajtja végre: először az osztálynál X, majd az osztálynál Y.
A tükrözés előnyeit szemléltető példa : egy objektum szerializálása JSON -ba . Reflexió nélkül szükséges lenne kifejezetten megadni az összes osztálymezőnevet, és hivatkozni az értékükre a sorosításhoz. De a tükrözés lehetővé teszi a program számára, hogy meghatározza az összes rendelkezésre álló mezőt, és megkapja a szöveges nevét. Így a szerializálás minden objektum számára elérhetővé válik extra kód írása nélkül.
A tükrözést támogató programozási nyelveken írt programok további funkciókkal vannak ellátva, amelyeket alacsony szintű nyelveken nehéz megvalósítani. Néhányat felsorolunk közülük:
Ezeket a funkciókat többféleképpen lehet megvalósítani. A MOO nyelvben a reflexió a napi programozási idióma része. Minden meghívott metódus a kontextusban kap információt arról, hogy honnan hívják, és hivatkozásokat azokra az objektumokra, amelyekhez tartoznak. A biztonságot programozottan szabályozzák a hívási verem segítségével: a callers() meghívása a metódusok listájának lekéréséhez; ellenőrzi, hogy a hívók()[1] letiltotta-e magát.
A lefordított nyelvek a futási környezetükre támaszkodnak, hogy a programokat a forráskódjukkal kapcsolatos információkkal látják el. Például egy Objective-C- re fordított végrehajtható fájl egy blokkba írja az összes metódus nevét, és létrehoz egy keresőtáblát. Az olyan lefordított nyelveken, amelyek támogatják a függvények futás közbeni létrehozását, mint például a Common Lisp , a futási környezetnek tartalmaznia kell egy fordítót és egy értelmezőt.
A tükrözés megvalósítása olyan nyelveken, amelyek nem támogatják, a programtranszformációs rendszer segítségével történik a forráskód változásainak automatikus nyomon követésére.
Példa C# -ban, amelyben létrejön fooaz osztály példánya, Fooés egy metódushívás történik Hello, amely nem használ tükrözést, és azt használja:
// Reflexió nélkül new Foo (). szia (); // Reflexióval Type type = System . típus . GetType ( "foo" ); var foo = Aktivátor . CreateInstance ( típus ); fú . Gettype (). GetMethod ( "Hello" ). Invoke ( foo , null );Hasonló példa az ECMAScript , a JavaScript és az ActionScript számára :
// Reflexió nélkül new Foo (). szia () // Reflexióval // feltételezve, hogy Foo ebben az újban ez [ ' Foo' ]()[ 'hello' ]() // nincsenek feltételezések new ( eval ( 'Foo' ))()[ 'hello' ]()