Aby uzyskać dostęp do pól prywatnych, musisz je pobrać z zadeklarowanych pól klasy, a następnie udostępnić je:
Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException
EDYCJA : jak skomentowali aperkins , zarówno dostęp do pola, ustawienie go jako dostępnego, jak i odzyskanie wartości może wyrzucić Exception
s, chociaż jedyne zaznaczone wyjątki, o których należy pamiętać, zostały skomentowane powyżej.
Zostanie NoSuchFieldException
rzucony, jeśli poprosisz o pole o nazwie, która nie odpowiada zadeklarowanemu polu.
obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException
Zostanie IllegalAccessException
wyrzucony, jeśli pole nie będzie dostępne (na przykład, jeśli jest prywatne i nie zostało udostępnione przez brak f.setAccessible(true)
linii).
Do RuntimeException
s, które mogą być rzucane są znakami SecurityException
s (jeśli JVM użytkownika SecurityManager
nie pozwalają na zmianę dostępności w polu), lub IllegalArgumentException
s, jeśli spróbujesz i dostęp boiska na obiekcie nie typu dziedzinie swojej klasie za:
f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type
getDeclaredField()
nie znajduje pól, jeśli są zdefiniowane w klasach nadrzędnych - musisz także iterować w górę przez hierarchię klas nadrzędnych, wzywającgetDeclaredField()
każde z nich, aż znajdziesz dopasowanie (po którym możesz zadzwonićsetAccessible(true)
) lub dojdzieszObject
.private
pól innych niż pola. Zapobiega przypadkowemu dostępowi.Spróbuj
FieldUtils
z apache commons-lang3:źródło
Refleksja to nie jedyny sposób na rozwiązanie problemu (dostęp do prywatnej funkcjonalności / zachowania klasy / komponentu)
Alternatywnym rozwiązaniem jest wyodrębnienie klasy z pliku .jar, dekompilacja jej za pomocą (powiedzmy) Jode lub Jad , zmiana pola (lub dodanie akcesorium) i ponowne skompilowanie jej z oryginalnym plikiem .jar. Następnie umieść nową .class przed ścieżką
.jar
klasy lub ponownie włóż ją do.jar
. (narzędzie jar umożliwia wyodrębnienie i ponowne włożenie do istniejącego pliku .jar)Jak zauważono poniżej, rozwiązuje to szerszy problem dostępu / zmiany stanu prywatnego, a nie tylko dostępu / zmiany pola.
Oczywiście wymaga
.jar
to podpisania.źródło
Jeszcze jedna opcja, o której jeszcze nie wspomniano: użyj Groovy . Groovy pozwala na dostęp do prywatnych zmiennych instancji jako efekt uboczny projektu języka. Niezależnie od tego, czy masz getter dla tego pola, możesz po prostu użyć
źródło
Za pomocą Reflection in Java możesz uzyskać dostęp do wszystkich
private/public
pól i metod jednej klasy do drugiej. Ale zgodnie z dokumentacją Oracle w wadach sekcji zalecili:„Ponieważ odbicie umożliwia kodowi wykonywanie operacji, które byłyby nielegalne w przypadku kodu nieodblaskowego, takich jak dostęp do prywatnych pól i metod, użycie odbicia może spowodować nieoczekiwane skutki uboczne, które mogą sprawić, że kod będzie niefunkcjonalny i może zniszczyć przenośność. Kod odblaskowy niszczy abstrakcje i dlatego może zmieniać zachowanie wraz z aktualizacjami platformy „
tutaj są następujące przyciągania kodu w celu zademonstrowania podstawowych koncepcji Reflection
Refleksja 1.java
Reflection2.java
Mam nadzieję, że to pomoże.
źródło
Jak wspomina oxbow_lakes, możesz użyć refleksji, aby obejść ograniczenia dostępu (zakładając, że Twój SecurityManager na to pozwoli).
To powiedziawszy, jeśli ta klasa jest tak źle zaprojektowana, że sprawia, że uciekasz się do takiego hakowania, być może powinieneś poszukać alternatywy. Pewnie, że ten mały hack może cię zaoszczędzić kilka godzin, ale ile to będzie kosztowało cię w dalszej drodze?
źródło
Skorzystaj ze środowiska Soot Java Optimization, aby bezpośrednio zmodyfikować kod bajtowy. http://www.sable.mcgill.ca/soot/
Soot jest całkowicie napisany w Javie i działa z nowymi wersjami Java.
źródło
Musisz wykonać następujące czynności:
źródło
Jeśli używasz Springa, ReflectionTestUtils zapewnia kilka przydatnych narzędzi, które pomagają tutaj przy minimalnym wysiłku. Jest opisany jako „do użytku w scenariuszach testów jednostkowych i integracyjnych” . Istnieje również podobna klasa o nazwie ReflectionUtils, ale jest ona opisana jako „przeznaczona wyłącznie do użytku wewnętrznego” - zobacz tę odpowiedź, aby zapoznać się z interpretacją tego, co to oznacza.
Aby rozwiązać opublikowany przykład:
źródło
ReflectionTestUtils
ponieważ w moim doświadczeniu potrzebowałem tego rodzaju rzeczy tylko w sytuacji testowej).Tylko dodatkowa uwaga na temat odbicia: zaobserwowałem w niektórych szczególnych przypadkach, gdy kilka klas o tej samej nazwie istnieje w różnych pakietach, to odbicie zastosowane w górnej odpowiedzi może nie wybrać właściwej klasy z obiektu. Jeśli więc wiesz, co to jest pakiet.klasa obiektu, lepiej uzyskać dostęp do jego wartości pola prywatnego w następujący sposób:
(To jest przykładowa klasa, która nie działała dla mnie)
źródło
Możesz użyć @JailBreak Manifold do bezpośredniego, bezpiecznego dla Java odbicie typu:
@JailBreak
odblokowujefoo
zmienną lokalną w kompilatorze dla bezpośredniego dostępu do wszystkich członków wFoo
hierarchii.Podobnie możesz użyć metody rozszerzenia jailbreak () do jednorazowego użytku:
Za pomocą tej
jailbreak()
metody można uzyskać dostęp do dowolnego członka wFoo
hierarchii.W obu przypadkach kompilator rozwiązuje dostęp do pola w sposób bezpieczny, tak jak w polu publicznym, podczas gdy kolektor generuje dla ciebie skuteczny kod odbicia pod maską.
Dowiedz się więcej o kolektorze .
źródło
Narzędzie XrayInterface jest dość łatwe . Po prostu zdefiniuj brakujące elementy pobierające / ustawiające, np
i xray swój źle zaprojektowany projekt:
Wewnętrznie polega to na refleksji.
źródło
Spróbuj obejść problem w przypadku, którego calass, który chcesz ustawić / uzyskać dane, jest jedną z twoich własnych klas.
Wystarczy utworzyć
public setter(Field f, Object value)
ipublic Object getter(Field f)
do tego. Możesz nawet samodzielnie przeprowadzić kontrolę bezpieczeństwa wewnątrz tych funkcji członkowskich. Np. Dla setera:Oczywiście, teraz musisz dowiedzieć się
java.lang.reflect.Field
osString
przed ustawieniem wartości pola.Używam tej techniki w ogólnym narzędziu mapującym ResultSet-to-and-from-model-mapper.
źródło