Czym jest Refleksja?
Refleksja to API, które umożliwia tworzenie instancji żądanej klasy za pomocą obiektu typu Class załadowanego do obszaru sterty oraz dostęp do pól i metod instancji niezależnie od modyfikatorów dostępu.
W tym kontekście, załadowana klasa oznacza, że ładowarka klas JVM ukończyła ładowanie pliku klasy, a następnie utworzyła obiekt typu Classzawierający informacje o tej klasie i zapisała go w obszarze sterty. Należy pamiętać, że różni się to od obiektów tworzonych za pomocą słowa kluczowego new. Jeśli nie rozumiesz dobrze obiektu typu Class, zapoznaj się z dokumentacją JDK dla java.lang.class.
Sposób użycia
Przed użyciem refleksji należy pobrać obiekt typu Class załadowany do obszaru sterty. Istnieją trzy sposoby na to.
- Pobranie za pomocą Klasa.class
- Pobranie za pomocą Instancja.getClass()
- Pobranie za pomocą Class.forName("NazwaKlasy")
Można zauważyć, że instancje typu Class uzyskane trzema metodami są identyczne. Niezależnie od użytej metody, wartość skrótu jest taka sama, więc należy wybrać metodę odpowiednią do sytuacji.
Teraz, mając obiekt typu Class, możemy utworzyć instancję danej klasy oraz uzyskać dostęp do pól i metod instancji niezależnie od modyfikatorów dostępu. Najpierw spróbujmy utworzyć instancję klasy.
Za pomocą metody getConstructor() można uzyskać konstruktor, a za pomocą metody newInstance() można dynamicznie utworzyć instancję Member.
Na koniec spróbujmy uzyskać dostęp do pól i metod instancji niezależnie od modyfikatorów dostępu.
Za pomocą metody getDeclaredFileds() można pobrać wszystkie zmienne instancji klasy, a za pomocą metody get() można zwrócić wartość pola, a za pomocą metody set() można zmodyfikować wartość pola. Należy pamiętać, że podczas uzyskiwania dostępu do pola z modyfikatorem dostępu private należy ustawić parametr metody setAccessible() na true.
W przypadku metod, można je pobrać za pomocą metody getDeclaredMethod(). Metoda ta przyjmuje nazwę metody i typ parametru jako parametry. Podobnie jak w przypadku pól, w przypadku metod z modyfikatorem dostępu private należy ustawić parametr setAccessible() na true. Na koniec, za pomocą metody invoke() można wywołać metodę uzyskaną za pomocą API refleksji.
Zalety i wady
- Zalety
- Zapewnia elastyczność, umożliwiając tworzenie instancji klas i uzyskiwanie dostępu do pól i metod w czasie wykonywania, niezależnie od modyfikatorów dostępu, co pozwala na wykonywanie wymaganych operacji.
- Wady
- Narusza zasadę hermetyzacji.
- Tworzenie instancji w czasie wykonywania uniemożliwia sprawdzenie typu w czasie kompilacji.
- Tworzenie instancji w czasie wykonywania utrudnia śledzenie przepływu programu.
- Dostęp do pól i metod za pomocą refleksji jest wolniejszy niż bezpośredni dostęp (chociaż nie zawsze).
Powody użycia
API refleksji umożliwia dostęp do informacji o klasie w czasie wykonywania i manipulowanie klasą w dowolny sposób. Możliwe jest nawet manipulowanie polami i metodami zadeklarowanymi jako private. Ponieważ narusza to zasadę hermetyzacji, która jest ważna w projektowaniu obiektowym, może wydawać się, że jest to technika, której należy unikać.
W przypadku małych aplikacji konsolowych, programista może w czasie kompilacji łatwo określić wszystkie obiekty, które będą używane w programie, oraz zależności między nimi. Jednak w przypadku dużych projektów, takich jak frameworki, trudno jest śledzić wszystkie obiekty i zależności. W takich przypadkach refleksja może być użyta do dynamicznego tworzenia klas i budowania zależności.
Na przykład, w przypadku fabryki Beanów Spring, wystarczy dodać adnotacje @Controller, @Service, @Repository, aby fabryka Beanów automatycznie tworzyła i zarządzała klasami z tymi adnotacjami. Programista nie informuje fabryki Beanów o tych klasach, ale jest to możliwe dzięki refleksji. W czasie wykonywania fabryka Beanów wyszukuje klasy z adnotacjami, a następnie za pomocą refleksji tworzy instancje tych klas, wstrzykuje wymagane pola i zapisuje je w fabryce Beanów.
Oczywiście, jak wspomniano wcześniej, narusza to hermetyzację, więc należy używać jej tylko wtedy, gdy jest to absolutnie konieczne.
Komentarze0