답변:
Thread.currentThread().getStackTrace()
일반적으로 호출하는 메소드를 포함하지만 함정이 있습니다 ( Javadoc 참조 ).
일부 가상 머신은 경우에 따라 스택 추적에서 하나 이상의 스택 프레임을 생략 할 수 있습니다. 극단적 인 경우,이 스레드에 관한 스택 추적 정보가없는 가상 머신은이 메소드에서 길이가 0 인 배열을 리턴 할 수 있습니다.
기술적으로 이것은 작동합니다 ...
String name = new Object(){}.getClass().getEnclosingMethod().getName();
그러나 컴파일 시간 동안 새로운 익명의 내부 클래스가 만들어집니다 (예 :) YourClass$1.class
. 따라서이 .class
트릭을 배포하는 각 방법에 대한 파일 이 생성됩니다 . 또한 런타임 동안 호출 할 때마다 사용하지 않는 객체 인스턴스가 생성됩니다. 따라서 이것은 허용 가능한 디버그 트릭 일 수 있지만 상당한 오버 헤드가 있습니다.
이 트릭의 장점은 주석 및 매개 변수 이름을 포함하여 메소드의 다른 모든 정보를 검색하는 데 사용할 수있는 getEncosingMethod()
리턴 java.lang.reflect.Method
입니다. 이를 통해 동일한 이름을 가진 특정 메소드 (방법 과부하)를 구별 할 수 있습니다.
getEnclosingMethod()
이 속임수 의 JavaDoc에 따르면 SecurityException
동일한 클래스 로더를 사용하여 내부 클래스를로드해야하므로 as를 던져서는 안됩니다. 따라서 보안 관리자가 있어도 액세스 조건을 확인할 필요가 없습니다.
getEnclosingConstructor()
생성자 에 사용해야 합니다. (명명 된) 메소드 외부의 블록 중에는을 getEnclosingMethod()
리턴합니다 null
.
getEnclosingMethod
클래스가 정의 된 메소드의 이름을 가져옵니다. this.getClass()
전혀 도움이되지 않습니다. @wutzebaer 왜 당신이 필요합니까? 이미 액세스 할 수 있습니다.
2009 년 1 월 : @Bombe의주의 사항 을 염두에두고
전체 코드를 작성합니다 .
/**
* Get the method name for a depth in call stack. <br />
* Utility function
* @param depth depth in the call stack (0 means current method, 1 means call method, ...)
* @return method name
*/
public static String getMethodName(final int depth)
{
final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
//System. out.println(ste[ste.length-depth].getClassName()+"#"+ste[ste.length-depth].getMethodName());
// return ste[ste.length - depth].getMethodName(); //Wrong, fails for depth = 0
return ste[ste.length - 1 - depth].getMethodName(); //Thank you Tom Tresansky
}
2011 년 12 월 업데이트 :
푸른 의견 :
JRE 6을 사용하고 잘못된 메소드 이름을 제공합니다.
내가 쓰면 작동ste[2 + depth].getMethodName().
0
입니다getStackTrace()
,1
이다getMethodName(int depth)
와2
메소드를 호출합니다.
virgo47 의 답변 ( 공개됨 )은 실제로 메소드 이름을 다시 얻기 위해 적용 할 올바른 색인을 계산합니다.
StackTraceElement
디버깅 목적으로 모든 배열 을 인쇄하고 'main'이 실제로 올바른 방법인지 확인 하려고 했 습니까?
ste[2 + depth].getMethodName()
. 0은 getStackTrace()
1 getMethodName(int depth)
, 2는 2 호출 방법입니다. @ virgo47의 답변 도 참조하십시오 .
이 코드를 사용하여 스택 추적 인덱스의 잠재적 변동성을 완화했습니다. 이제 methodName util을 호출하면됩니다.
public class MethodNameTest {
private static final int CLIENT_CODE_STACK_INDEX;
static {
// Finds out the index of "this code" in the returned stack trace - funny but it differs in JDK 1.5 and 1.6
int i = 0;
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
i++;
if (ste.getClassName().equals(MethodNameTest.class.getName())) {
break;
}
}
CLIENT_CODE_STACK_INDEX = i;
}
public static void main(String[] args) {
System.out.println("methodName() = " + methodName());
System.out.println("CLIENT_CODE_STACK_INDEX = " + CLIENT_CODE_STACK_INDEX);
}
public static String methodName() {
return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX].getMethodName();
}
}
오버 엔지니어링 된 것 같지만 JDK 1.5의 고정 번호가 있었고 JDK 1.6으로 옮길 때 약간 바뀌 었다는 것이 약간 놀랐습니다. 이제는 Java 6/7에서 동일하지만 결코 알 수 없습니다. 런타임 동안 해당 인덱스의 변경을 증명하는 것은 아니지만 HotSpot이 그렇게 나쁘지 않기를 바랍니다. :-)
public class SomeClass {
public void foo(){
class Local {};
String name = Local.class.getEnclosingMethod().getName();
}
}
name의 값은 foo입니다.
null
이 두 가지 옵션 모두 Java에서 작동합니다.
new Object(){}.getClass().getEnclosingMethod().getName()
또는:
Thread.currentThread().getStackTrace()[1].getMethodName()
내가 찾은 가장 빠른 방법 은 다음과 같습니다.
import java.lang.reflect.Method;
public class TraceHelper {
// save it static to have it available on every call
private static Method m;
static {
try {
m = Throwable.class.getDeclaredMethod("getStackTraceElement",
int.class);
m.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getMethodName(final int depth) {
try {
StackTraceElement element = (StackTraceElement) m.invoke(
new Throwable(), depth + 1);
return element.getMethodName();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
원시 메소드 getStackTraceElement (int depth)에 직접 액세스합니다. 그리고 접근 가능한 메소드를 정적 변수에 저장합니다.
new Throwable().getStackTrace()
가 걸리고 사용 에는 5614ms가 걸렸습니다.
다음 코드를 사용하십시오.
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st
String methodName = e.getMethodName();
System.out.println(methodName);
이것은 virgo47의 답변 (위) 에 대한 확장입니다 .
현재 및 호출 클래스 / 메소드 이름을 가져 오기위한 정적 메소드를 제공합니다.
/* Utility class: Getting the name of the current executing method
* /programming/442747/getting-the-name-of-the-current-executing-method
*
* Provides:
*
* getCurrentClassName()
* getCurrentMethodName()
* getCurrentFileName()
*
* getInvokingClassName()
* getInvokingMethodName()
* getInvokingFileName()
*
* Nb. Using StackTrace's to get this info is expensive. There are more optimised ways to obtain
* method names. See other stackoverflow posts eg. /programming/421280/in-java-how-do-i-find-the-caller-of-a-method-using-stacktrace-or-reflection/2924426#2924426
*
* 29/09/2012 (lem) - added methods to return (1) fully qualified names and (2) invoking class/method names
*/
package com.stackoverflow.util;
public class StackTraceInfo
{
/* (Lifted from virgo47's stackoverflow answer) */
private static final int CLIENT_CODE_STACK_INDEX;
static {
// Finds out the index of "this code" in the returned stack trace - funny but it differs in JDK 1.5 and 1.6
int i = 0;
for (StackTraceElement ste: Thread.currentThread().getStackTrace())
{
i++;
if (ste.getClassName().equals(StackTraceInfo.class.getName()))
{
break;
}
}
CLIENT_CODE_STACK_INDEX = i;
}
public static String getCurrentMethodName()
{
return getCurrentMethodName(1); // making additional overloaded method call requires +1 offset
}
private static String getCurrentMethodName(int offset)
{
return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getMethodName();
}
public static String getCurrentClassName()
{
return getCurrentClassName(1); // making additional overloaded method call requires +1 offset
}
private static String getCurrentClassName(int offset)
{
return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getClassName();
}
public static String getCurrentFileName()
{
return getCurrentFileName(1); // making additional overloaded method call requires +1 offset
}
private static String getCurrentFileName(int offset)
{
String filename = Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getFileName();
int lineNumber = Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getLineNumber();
return filename + ":" + lineNumber;
}
public static String getInvokingMethodName()
{
return getInvokingMethodName(2);
}
private static String getInvokingMethodName(int offset)
{
return getCurrentMethodName(offset + 1); // re-uses getCurrentMethodName() with desired index
}
public static String getInvokingClassName()
{
return getInvokingClassName(2);
}
private static String getInvokingClassName(int offset)
{
return getCurrentClassName(offset + 1); // re-uses getCurrentClassName() with desired index
}
public static String getInvokingFileName()
{
return getInvokingFileName(2);
}
private static String getInvokingFileName(int offset)
{
return getCurrentFileName(offset + 1); // re-uses getCurrentFileName() with desired index
}
public static String getCurrentMethodNameFqn()
{
return getCurrentMethodNameFqn(1);
}
private static String getCurrentMethodNameFqn(int offset)
{
String currentClassName = getCurrentClassName(offset + 1);
String currentMethodName = getCurrentMethodName(offset + 1);
return currentClassName + "." + currentMethodName ;
}
public static String getCurrentFileNameFqn()
{
String CurrentMethodNameFqn = getCurrentMethodNameFqn(1);
String currentFileName = getCurrentFileName(1);
return CurrentMethodNameFqn + "(" + currentFileName + ")";
}
public static String getInvokingMethodNameFqn()
{
return getInvokingMethodNameFqn(2);
}
private static String getInvokingMethodNameFqn(int offset)
{
String invokingClassName = getInvokingClassName(offset + 1);
String invokingMethodName = getInvokingMethodName(offset + 1);
return invokingClassName + "." + invokingMethodName;
}
public static String getInvokingFileNameFqn()
{
String invokingMethodNameFqn = getInvokingMethodNameFqn(2);
String invokingFileName = getInvokingFileName(2);
return invokingMethodNameFqn + "(" + invokingFileName + ")";
}
}
현재 메소드를 호출 한 메소드의 이름을 얻으려면 다음을 사용할 수 있습니다.
new Exception("is not thrown").getStackTrace()[1].getMethodName()
이것은 내 안드로이드 폰뿐만 아니라 MacBook에서도 작동합니다.
나는 또한 시도했다 :
Thread.currentThread().getStackTrace()[1]
그러나 안드로이드는 "getStackTrace"를 반환합니다.
Thread.currentThread().getStackTrace()[2]
근데 MacBook에서 틀린 답을 얻습니다
getStackTrace()[0]
결과 getStackTrace()[1]
. 보다 사용하는 것이 좋습니다 . YMMV.
Thread.currentThread().getStackTrace()[2]
Util.java :
public static String getCurrentClassAndMethodNames() {
final StackTraceElement e = Thread.currentThread().getStackTrace()[2];
final String s = e.getClassName();
return s.substring(s.lastIndexOf('.') + 1, s.length()) + "." + e.getMethodName();
}
SomeClass.java :
public class SomeClass {
public static void main(String[] args) {
System.out.println(Util.getCurrentClassAndMethodNames()); // output: SomeClass.main
}
}
final StackTraceElement e = Thread.currentThread().getStackTrace()[2];
공장; e.getClassName();
전체 클래스 이름을 e.getMethodName()
반환하고 methon 이름을 반환하십시오.
getStackTrace()[2]
잘못된, 그것은이어야 getStackTrace()[3]
때문에 [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] 함수 A ()이 하나를 호출
이것은 StackWalker
Java 9부터 사용할 수 있습니다 .
public static String getCurrentMethodName() {
return StackWalker.getInstance()
.walk(s -> s.skip(1).findFirst())
.get()
.getMethodName();
}
public static String getCallerMethodName() {
return StackWalker.getInstance()
.walk(s -> s.skip(2).findFirst())
.get()
.getMethodName();
}
StackWalker
는 게 으르도록 설계되었으므로 Thread.getStackTrace
전체 호출 스택에 대한 배열을 열심히 만드는 것보다 더 효율적일 수 있습니다 . 자세한 내용은 JEP를 참조하십시오.
대체 방법은 예외를 생성하지만 예외는 발생시키지 않고 스택 추적 데이터를 가져 오는 해당 객체를 사용하는 것입니다. 엔 클로징 방법은 일반적으로 JVM이 해당 정보를 저장하는 한 다른 방법 에서처럼 인덱스 0에 있기 때문입니다. 위에 언급했듯이. 그러나 이것이 가장 저렴한 방법은 아닙니다.
에서 Throwable.getStackTrace () (이 적어도 자바 5 이후 같은되었습니다)
배열의 0 번째 요소 (배열의 길이가 0이 아닌 것으로 가정)는 스택의 맨 위를 나타내며, 이는 시퀀스에서 마지막 메소드 호출입니다. 일반적 으로이 던지기 가능 항목을 작성하여 던지는 지점입니다.
아래 스 니펫은 클래스가 정적이 아닌 것으로 가정합니다 (getClass () 때문에).
System.out.printf("Class %s.%s\n", getClass().getName(), new Exception("is not thrown").getStackTrace()[0].getMethodName());
String methodName =Thread.currentThread().getStackTrace()[1].getMethodName();
System.out.println("methodName = " + methodName);
이것을 사용하는 솔루션이 있습니다 (Android에서)
/**
* @param className fully qualified className
* <br/>
* <code>YourClassName.class.getName();</code>
* <br/><br/>
* @param classSimpleName simpleClassName
* <br/>
* <code>YourClassName.class.getSimpleName();</code>
* <br/><br/>
*/
public static void getStackTrace(final String className, final String classSimpleName) {
final StackTraceElement[] steArray = Thread.currentThread().getStackTrace();
int index = 0;
for (StackTraceElement ste : steArray) {
if (ste.getClassName().equals(className)) {
break;
}
index++;
}
if (index >= steArray.length) {
// Little Hacky
Log.w(classSimpleName, Arrays.toString(new String[]{steArray[3].getMethodName(), String.valueOf(steArray[3].getLineNumber())}));
} else {
// Legitimate
Log.w(classSimpleName, Arrays.toString(new String[]{steArray[index].getMethodName(), String.valueOf(steArray[index].getLineNumber())}));
}
}
현재 실행중인 메소드의 이름을 얻는 의도가 무엇인지 모르겠지만, 디버깅 목적으로 만 사용되는 경우 "logback"과 같은 로깅 프레임 워크가 도움이 될 수 있습니다. 예를 들어, 로그 백에서 로깅 구성에 "% M"패턴 을 사용 하기 만하면 됩니다. 그러나 성능이 저하 될 수 있으므로주의해서 사용해야합니다.
알고 싶은 이름의 메소드가 junit 테스트 메소드 인 경우 junit TestName 규칙을 사용할 수 있습니다. https://stackoverflow.com/a/1426730/3076107
여기에 대부분의 답변이 잘못된 것 같습니다.
public static String getCurrentMethod() {
return getCurrentMethod(1);
}
public static String getCurrentMethod(int skip) {
return Thread.currentThread().getStackTrace()[1 + 1 + skip].getMethodName();
}
예:
public static void main(String[] args) {
aaa();
}
public static void aaa() {
System.out.println("aaa -> " + getCurrentMethod( ) );
System.out.println("aaa -> " + getCurrentMethod(0) );
System.out.println("main -> " + getCurrentMethod(1) );
}
출력 :
aaa -> aaa
aaa -> aaa
main -> main
나는 maklemenz의 대답을 약간 다시 작성했습니다 .
private static Method m;
static {
try {
m = Throwable.class.getDeclaredMethod(
"getStackTraceElement",
int.class
);
}
catch (final NoSuchMethodException e) {
throw new NoSuchMethodUncheckedException(e);
}
catch (final SecurityException e) {
throw new SecurityUncheckedException(e);
}
}
public static String getMethodName(int depth) {
StackTraceElement element;
final boolean accessible = m.isAccessible();
m.setAccessible(true);
try {
element = (StackTraceElement) m.invoke(new Throwable(), 1 + depth);
}
catch (final IllegalAccessException e) {
throw new IllegalAccessUncheckedException(e);
}
catch (final InvocationTargetException e) {
throw new InvocationTargetUncheckedException(e);
}
finally {
m.setAccessible(accessible);
}
return element.getMethodName();
}
public static String getMethodName() {
return getMethodName(1);
}
MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();
getEnclosingMethod()
NullPointerException
Java 7에서 나를 위해 a 를 던졌습니다 .
이 접근법의 문제점 :
class Example {
FileOutputStream fileOutputStream;
public Example() {
//System.out.println("Example.Example()");
debug("Example.Example()",false); // toggle
try {
fileOutputStream = new FileOutputStream("debug.txt");
} catch (Exception exception) {
debug(exception + Calendar.getInstance().getTime());
}
}
private boolean was911AnInsideJob() {
System.out.println("Example.was911AnInsideJob()");
return true;
}
public boolean shouldGWBushBeImpeached(){
System.out.println("Example.shouldGWBushBeImpeached()");
return true;
}
public void setPunishment(int yearsInJail){
debug("Server.setPunishment(int yearsInJail=" + yearsInJail + ")",true);
}
}
그리고 사람들이 사용에 열중하기 전에 System.out.println(...)
항상 출력을 리디렉션 할 수 있도록 몇 가지 방법을 만들어야합니다.
private void debug (Object object) {
debug(object,true);
}
private void dedub(Object object, boolean debug) {
if (debug) {
System.out.println(object);
// you can also write to a file but make sure the output stream
// ISN'T opened every time debug(Object object) is called
fileOutputStream.write(object.toString().getBytes());
}
}