Последний элемент массива представляет нижнюю часть стека, которая является наименее последним вызовом метода в последовательности.
У StackTraceElement есть getClassName(), getFileName(), getLineNumber() и getMethodName().
Вам придется поэкспериментировать, чтобы определить, какой индекс вы хотите (вероятно, stackTraceElements[1] или [2]).
Ответ 2
Примечание: если вы используете Java 9 или более поздней версии, вам следует использовать StackWalker.getCallerClass() как описано в ответе Али Дехгани.
Сравнение различных методов, приведенное ниже, в основном интересно по исторической причине.
Альтернативное решение можно найти в комментарии к этому запросу на улучшение. Он использует getClassContext() пользовательский метод SecurityManager и, похоже, работает быстрее, чем метод трассировки стека.
Следующая программа проверяет скорость различных предложенных методов (самая интересная часть находится во внутреннем классе SecurityManagerMethod):
/** * Test the speed of various methods for getting the caller class name */ publicclassTestGetCallerClassName {
/** * Abstract class for testing different methods of getting the caller class name */ privatestaticabstractclassGetCallerClassNameMethod { publicabstract String getCallerClassName(int callStackDepth); publicabstract String getMethodName(); }
/** * Uses the internal Reflection class */ privatestaticclassReflectionMethodextendsGetCallerClassNameMethod { public String getCallerClassName(int callStackDepth) { return sun.reflect.Reflection.getCallerClass(callStackDepth).getName(); }
public String getMethodName() { return"Reflection"; } }
/** * Get a stack trace from the current thread */ privatestaticclassThreadStackTraceMethodextendsGetCallerClassNameMethod { public String getCallerClassName(int callStackDepth) { return Thread.currentThread().getStackTrace()[callStackDepth].getClassName(); }
public String getMethodName() { return"Current Thread StackTrace"; } }
/** * Get a stack trace from a new Throwable */ privatestaticclassThrowableStackTraceMethodextendsGetCallerClassNameMethod {
public String getCallerClassName(int callStackDepth) { returnnewThrowable().getStackTrace()[callStackDepth].getClassName(); }
public String getMethodName() { return"Throwable StackTrace"; } }
/** * Use the SecurityManager.getClassContext() */ privatestaticclassSecurityManagerMethodextendsGetCallerClassNameMethod { public String getCallerClassName(int callStackDepth) { return mySecurityManager.getCallerClassName(callStackDepth); }
public String getMethodName() { return"SecurityManager"; }
/** * A custom security manager that exposes the getClassContext() information */ staticclassMySecurityManagerextendsSecurityManager { public String getCallerClassName(int callStackDepth) { return getClassContext()[callStackDepth].getName(); } }
/** * Test all four methods */ publicstaticvoidmain(String[] args) { testMethod(newReflectionMethod()); testMethod(newThreadStackTraceMethod()); testMethod(newThrowableStackTraceMethod()); testMethod(newSecurityManagerMethod()); }
privatestaticvoidtestMethod(GetCallerClassNameMethod method) { longstartTime= System.nanoTime(); StringclassName=null; for (inti=0; i < 1000000; i++) { className = method.getCallerClassName(2); } printElapsedTime(method.getMethodName(), startTime); }
Метод внутреннего отражения намного быстрее других. Получение трассировки стека из вновь созданного Throwable быстрее, чем из текущего Thread. И среди внешних способов поиска вызывающего класса пользовательский SecurityManager кажется самым быстрым.
Обновить
Как лайоми указывает в этом комментарии, sun.reflect.Reflection.getCallerClass() метод был отключен по умолчанию в обновлении 40 Java 7 и полностью удален в Java 8. Подробнее об этом читайте в этой проблеме в базе данных ошибок Java.
Обновление 2
Как обнаружил zammbi, Oracle была вынуждена отказаться от изменения, которое удалило sun.reflect.Reflection.getCallerClass(). Он по-прежнему доступен в Java 8 (но устарел).
Обновление 3
3 года спустя: обновление по синхронизации с текущей JVM.
> java -version java version "1.8.0" Java(TM) SE Runtime Environment(build 1.8.0-b132) Java HotSpot(TM)64-Bit Server VM(build 25.0-b70, mixed mode) > java TestGetCallerClassName Reflection: 0.194s. Current Thread StackTrace: 3.887s. Throwable StackTrace: 3.173s. SecurityManager: 0.565s.
Ответ 3
Java 9 - JEP 259: Stack-Walking API
JEP 259 предоставляет эффективный стандартный API для обхода стека, который обеспечивает легкую фильтрацию и отложенный доступ к информации в трассировках стека. До появления Stack-Walking API распространенными способами доступа к фреймам стека были:
Throwable::getStackTrace и Thread::getStackTrace возвращает массив StackTraceElement объектов, которые содержат имя класса и имя метода каждого элемента трассировки стека.
SecurityManager::getClassContext это защищенный метод, который позволяет SecurityManager подклассу получать доступ к контексту класса.
JDK-внутренний sun.reflect.Reflection::getCallerClass метод, который вам все равно не следует использовать
Использование этих API обычно неэффективно:
Эти API требуют, чтобы виртуальная машина быстро делала снимок всего стека, и они возвращают информацию, представляющую весь стек. Невозможно избежать затрат на проверку всех фреймов, если вызывающую функцию интересуют только несколько верхних фреймов в стеке.
Чтобы найти класс непосредственного вызывающего объекта, сначала получите StackWalker:
Звучит так, как будто вы пытаетесь избежать передачи ссылки на this в метод. Передача this намного лучше, чем поиск вызывающей функции по текущей трассировке стека. Рефакторинг для более ООП дизайна еще лучше. Вам не обязательно знать вызывающего. При необходимости передайте объект обратного вызова.