有没有一种方法在Java中获取当前执行方法的名称?
从技术上讲,这样做是可行的...
String name = new Object(){}.getClass().getEnclosingMethod().getName();
然而,在编译时会创建一个新的匿名内部类(例如YourClass$1.class
)。因此,这将为每个使用该技巧的方法创建一个.class
文件。此外,每次调用期间都会创建一个未使用的对象实例。因此,这可能是一种可接受的调试技巧,但它确实带来了显着的开销。
这种技巧的优点是getEnclosingMethod()
返回java.lang.reflect.Method
,可以用于检索方法的所有其他信息,包括注释和参数名称。这使得可以区分具有相同名称的特定方法(方法重载)。
请注意,根据getEnclosingMethod()
的JavaDoc,这种技巧不应抛出SecurityException
,因为内部类应使用相同的类加载器进行加载。因此,即使存在安全管理器,也无需检查访问条件。
请注意:必须使用getEnclosingConstructor()
来获取构造函数。在(命名)方法之外的块中,getEnclosingMethod()
返回null
。
getEnclosingMethod
获取的是类所定义的方法的名称。this.getClass()
对你没有帮助。@wutzebaer 你为什么需要这样做呢?你已经可以访问它们了。 - Hazel TThread.currentThread().getStackTrace()
通常会包含您正在调用它的方法,但是有坑(请参见Javadoc):
某些虚拟机在某些情况下可能会从堆栈跟踪中省略一个或多个堆栈帧。 在极端情况下,允许没有关于此线程的堆栈跟踪信息的虚拟机从该方法返回零长度数组。
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月更新:
bluish评论说:
我使用JRE 6,它给我提供了错误的方法名称。
如果我写ste[2 + depth].getMethodName().
就可以了。
0
是getStackTrace()
,1
是getMethodName(int depth)
,而2
是调用方法。
StackTraceElement
数组以进行调试并查看'main'是否是正确的方法了吗? - VonCste[2 + depth].getMethodName()
就可以正常工作。其中0代表getStackTrace()
,1代表getMethodName(int depth)
,2代表调用方法。参见@virgo47答案。 - bluishpublic 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();
}
}
名称将具有值foo。
null
。 - Maarten Bodewes这两个选项都对我在Java中的工作有效:
new Object(){}.getClass().getEnclosingMethod().getName()
或者:Thread.currentThread().getStackTrace()[1].getMethodName()
java.lang.StackWalker
自Java 9以来,可以使用StackWalker
来完成此操作。
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获取更多信息。
我发现最快的方法是:
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()
则需要5614毫秒。 - achThrowable.getStackTraceElement(int)
方法。 - DenniesetAccessible(true)
现在也会失败。 - Holger使用以下代码:
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st
String methodName = e.getMethodName();
System.out.println(methodName);
public static String getCurrentMethodName() {
return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
}
Thread.currentThread().getStackTrace()
。这就是本地变量的作用,用于存储评估结果,以便您可以多次使用该结果而不是重复评估。 - Holger
StackWalker
的答案。您很久以前接受的答案现在已经过时。 - Honza ZidekStackWalker
的答案。你很久以前接受的答案现在已经过时了。 - undefinedjava.lang.StackWalker
解决方案:链接。 - Basil Bourque