Muszę znaleźć obiekt wywołujący metodę. Czy jest to możliwe przy użyciu stacktrace lub refleksji?
java
stack-trace
Satish
źródło
źródło
DontNameYourMethodFooException
jeśli metoda wywołująca nazywa się foo.Odpowiedzi:
Według Javadocs:
StackTraceElement
MagetClassName()
,getFileName()
,getLineNumber()
igetMethodName()
.Będziesz musiał eksperymentować, aby określić, który indeks chcesz (prawdopodobnie
stackTraceElements[1]
lub[2]
).źródło
Alternatywne rozwiązanie można znaleźć w komentarzu do tej prośby o ulepszenie . Wykorzystuje
getClassContext()
metodę niestandardowąSecurityManager
i wydaje się być szybsza niż metoda śledzenia stosu.Poniższy program testuje szybkość różnych sugerowanych metod (najciekawszy bit znajduje się w klasie wewnętrznej
SecurityManagerMethod
):Przykład danych wyjściowych z mojego MacBooka Intel Core 2 Duo 2,4 GHz z Javą 1.6.0_17:
Metoda wewnętrznego odbicia jest znacznie szybsza niż inne. Pobieranie śladu stosu z nowo utworzonego
Throwable
jest szybsze niż pobieranie z bieżącegoThread
. A wśród nie-wewnętrznych sposobów znajdowania klasy dzwoniącego zwyczajSecurityManager
wydaje się najszybszy.Aktualizacja
Jak lyomi wskazuje w tym komentarzu
sun.reflect.Reflection.getCallerClass()
metoda została domyślnie wyłączona w Java 7 aktualizacji 40 i usunięte całkowicie w Javie 8. Więcej na ten temat w tym numerze w bazie danych błędów Java .Aktualizacja 2
Jak stwierdził Zammbi , Oracle został zmuszony wycofać się ze zmiany, która usunęła
sun.reflect.Reflection.getCallerClass()
. Jest nadal dostępny w Javie 8 (ale jest przestarzały).Aktualizacja 3
3 lata później: aktualizacja harmonogramu z aktualną maszyną JVM.
źródło
Wygląda na to, że próbujesz uniknąć podania odwołania do
this
metody. Przekazywaniethis
jest o wiele lepsze niż znalezienie dzwoniącego przez bieżący ślad stosu. Refaktoryzacja do projektu OO jest jeszcze lepsza. Nie powinieneś znać dzwoniącego. Przekaż obiekt zwrotny, jeśli to konieczne.źródło
LoggerFactory.getLogger(MyClass.class)
której nie musiałem przekazywać literału klasowego. Nadal rzadko jest to właściwe.INotifyPropertyChanged
interfejsu .NET . Chociaż ten konkretny przykład nie jest w Javie, ten sam problem może się objawiać podczas próby modelowania pól / modułów pobierających jako ciągów dla Reflection.Java 9 - JEP 259: Interfejs API Walking-Walking
JEP 259 zapewnia wydajny standardowy interfejs API do chodzenia po stosie, który umożliwia łatwe filtrowanie i leniwy dostęp do informacji w śladach stosu. Przed interfejsem API Walking-Walking powszechne sposoby uzyskiwania dostępu do ramek stosu:
Korzystanie z tych interfejsów API jest zwykle nieefektywne:
Aby znaleźć klasę bezpośredniego rozmówcy, najpierw uzyskaj
StackWalker
:Następnie albo zadzwoń
getCallerClass()
:lub
walk
gdyStackFrame
s i uzyskać pierwszą poprzedzającyStackFrame
:źródło
Oneliner :
Pamiętaj, że może być konieczne zastąpienie 2 przez 1.
źródło
Ta metoda robi to samo, ale nieco prościej i być może nieco bardziej wydajna, a jeśli używasz odbicia, automatycznie pomija te klatki. Jedynym problemem jest to, że może nie być obecny w maszynach JVM innych niż Sun, chociaż jest zawarty w klasach wykonawczych JRockit 1.4 -> 1.6. (Chodzi o to, że nie jest to klasa publiczna ).
Jeśli chodzi o
realFramesToSkip
wartość, w wersjach Sun 1.5 i 1.6 VMjava.lang.System
, istnieje metoda chroniona pakietem o nazwie getCallerClass (), która wywołujesun.reflect.Reflection.getCallerClass(3)
, ale w mojej klasie narzędzi pomocniczych użyłem 4, ponieważ istnieje dodatkowa ramka klasy pomocniczej wezwanie.źródło
Na przykład, jeśli próbujesz uzyskać linię metody wywołującej w celu debugowania, musisz ominąć klasę Utility, w której
kodujesz te metody statyczne: (stary kod java1.4, tylko w celu zilustrowania potencjalnego użycia StackTraceElement)
źródło
Zrobiłem to wcześniej. Możesz po prostu utworzyć nowy wyjątek i pobrać ślad stosu bez rzucania go, a następnie zbadać ślad stosu. Jednak jak mówi druga odpowiedź, jest to niezwykle kosztowne - nie rób tego w ciasnej pętli.
Zrobiłem to już wcześniej dla narzędzia do rejestrowania w aplikacji, w której wydajność nie miała większego znaczenia (Wydajność rzadko w rzeczywistości ma tak naprawdę duże znaczenie - pod warunkiem, że wyświetlasz wynik działania, takiego jak szybkie kliknięcie przycisku).
To było zanim można było pobrać ślad stosu, wyjątki miały po prostu .printStackTrace (), więc musiałem przekierować System.out do strumienia mojego własnego stworzenia, a następnie (new Exception ()). PrintStackTrace (); Przekieruj System.out z powrotem i przeanalizuj strumień. Zabawne rzeczy.
źródło
źródło
Oto część kodu, który stworzyłem na podstawie wskazówek pokazanych w tym temacie. Mam nadzieję, że to pomoże.
(Prosimy o wszelkie sugestie dotyczące ulepszenia tego kodu, proszę powiedz mi)
Licznik:
A przedmiot:
źródło
LUB
źródło
użyj tej metody:
Przykład metody wywołującej Kod znajduje się tutaj: -
źródło