Mechanizm refleksji
Część lub nawet wszystkie informacje w artykule mogą być nieprawdziwe. Jako pozbawione źródeł mogą zostać zakwestionowane i usunięte.
Sprawdź w źródłach: Encyklopedia PWN • Google Books • Google Scholar • Federacja Bibliotek Cyfrowych • BazHum • BazTech • RCIN • Internet Archive (texts / inlibrary)
Dokładniejsze informacje o tym, co należy poprawić, być może znajdują się w dyskusji tego artykułu.
Po wyeliminowaniu niedoskonałości należy usunąć szablon {{Dopracować}} z tego artykułu.
Mechanizm refleksji – w informatyce, proces, dzięki któremu program komputerowy może być modyfikowany w trakcie działania w sposób zależny od własnego kodu oraz od zachowania w trakcie wykonania. Związany z nim paradygmat programowania to programowanie refleksyjne.
Refleksja pozwala zarządzać kodem tak, jakby był danymi. Używa się jej najczęściej do zmieniania standardowego zachowania już zdefiniowanych metod lub funkcji, a także do tworzenia własnych konstrukcji semantycznych modyfikujących język. Z drugiej strony kod wykorzystujący refleksję jest mniej czytelny i nie pozwala na sprawdzenie poprawności składniowej i semantycznej w trakcie kompilacji.
Przykład zastosowania mechanizmu refleksji stanowią języki programowania, w których każdy element kodu źródłowego reprezentowany jest strukturami danych dostępnymi dla programisty. Nazywa się je językami homoikonicznymi, a kod źródłowy ich programów jest w istocie danymi. Od decyzji programisty zależy, które jego fragmenty będą wartościowane, a które traktowane jak wartości stałe niewymagające obliczeń. Proces ten może być wielokierunkowy, np. część kodu źródłowego może zostać potraktowana jak dane, przekształcona, a następnie znów wartościowana – w ten sposób działają tzw. makra składniowe w dialektach języka Lisp.
Mechanizm refleksji jest najczęściej spotykany w językach wysokiego poziomu, szczególnie opartych na maszynie wirtualnej.
Przykłady
C#
Poniższy przykład demonstruje użycie refleksji w języku C Sharp używając pakietu System.Reflection
//bez refleksji Foo foo = new Foo(); foo.hello(); //z użyciem refleksji var type = Type.GetType("namespace.Foo"); // string powinien zawierać namespace naszej klasy var foo = Activator.CreateInstance(type); // inicjacja obiektu określonego typu MethodInfo inf = type.GetMethod("hello"); inf.Invoke(foo); // jako drugi parametr metoda Invoke przyjmuje tablicę Object[] są to parametry metody hello.
Objective-C
Poniższy przykład demonstruje użycie refleksji w języku Objective-C
// bez refleksji Foo *foo = [[Foo alloc] init]; [foo hello]; [foo release]; // z refleksją id foo = [[NSClassFromString(@"Foo") alloc] init]; SEL selector = NSSelectorFromString(@"hello"); [foo performSelector:selector]; [foo release];
Java
Poniższy przykład w języku Java wykorzystuje pakiet java.lang.reflect.
// bez refleksji Foo foo = new Foo(); foo.hello(); // z refleksją Class cl = Class.forName("Foo"); Method method = cl.getMethod("hello"); method.invoke(cl.newInstance());
Oba fragmenty tworzą instancję klasy Foo
, następnie wywołują metodę hello()
tej klasy. Różnica polega na tym, że w pierwszym fragmencie nazwa klasy i metody są częścią kodu źródłowego, podczas gdy w drugim fragmencie możliwe jest przeniesienie ich do zmiennych, których wartość jest ustalana w czasie wykonania kodu.
Mechanizm refleksji pozwala także na zdobywanie informacji o klasach w trakcie wykonania programu. W poniższym przykładzie Klasa Main
sprawdza jaki jest typ zwracany przez metody klasy Bar
.
public class Bar { public String fun(Integer i) { return "0" + i + ", zglos sie!"; } } import static java.lang.System.out; import java.lang.reflect.*; public class Main { public static void main(String[] args) throws Exception { String className = "Bar"; Class c = Class.forName(className); Method[] methodArr = c.getDeclaredMethods(); for (Method m : methodArr) { out.print("Klasa " + className + " ma metode '" + m.getName() + "'"); out.println(" ktora zwraca wartosc typu " + m.getReturnType()); } } }
Ruby
Przykład w języku Ruby, który dodaje metodę klasową once
, pozwalającą zaznaczyć, że dana funkcja składowa klasy ma być wykonywana tylko raz. Podprogram modyfikuje kod oznaczonych metod w taki sposób, że nadaje im nową nazwę. Pod starą nazwą umieszcza nową metodę, która buforuje wartość zwracaną przez pierwotnie zdefiniowaną funkcję, tym samym pozwalając się jej wykonać tylko raz.
# part of date.rb - date and time library # Author: Tadayoshi Funaba 1998-2008 class Date class << self def once(*ids) # :nodoc: -- restricted for id in ids module_eval <<-"end;" alias_method :__#{id.object_id}__, :#{id.to_s} private :__#{id.object_id}__ def #{id.to_s}(*args) @__ca__[#{id.object_id}] ||= __#{id.object_id}__(*args) end end; end end private :once end end
Inny przykład to rozszerzenie możliwości języka o konstrukcję automatycznie kasującą zawartość wskazanych przez programistę buforów, jeśli uruchomione zostaną wyszczególnione metody. Zadaniem metaprogramu jest tu również opakowanie metod, jednak zapamiętywane są identyfikatory ich obiektów a nie identyfikatory obiektów ich symbolicznych nazw. Metaprogram zawarto w przykładowym module BufferAffects
, który można pobrać z serwisu GitHub. Domieszkując ten moduł możemy korzystać z dodatkowych metod klasowych pozwalających na stosowanie w kodzie klauzul buffers_reset_method
i attr_affects_buffers
:
require 'bufferaffects' # http://gist.github.com/88178 class Main # domieszkowanie modułu extend BufferAffects # metoda opróżniająca wykorzystywany bufor buffers_reset_method :reset_path_buffer # pola które po zmianie powinny wpływać na # zawartość bufora attr_affects_buffers :subpart # standardowe akcesory pól attr_accessor :subpart, :otherpart # metoda opróżniająca bufor def reset_path_buffer(name) @path = nil p "uruchomiono reset dla #{name}" end # metoda z buforowanym wyjściem def path @path ||= @subpart.to_s + @otherpart.to_s end end # tworzenie nowego obiektu obj = Main.new # ustawianie jednego z pól # i wyświetlanie buforowanych wynikow obj.subpart = 'test' p obj.path obj.subpart = '1234' p obj.path
Linki zewnętrzne
- Java. Obiekty refleksyjne – artykuł wyjaśniający co to są refleksje i jak się je stosuje w Javie