我需要找到一个方法的调用者。是否可以使用堆栈跟踪或反射?
当前回答
使用方法:-
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
stackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
System.out.println(e.getMethodName());
方法示例代码的调用者在这里:-
public class TestString {
public static void main(String[] args) {
TestString testString = new TestString();
testString.doit1();
testString.doit2();
testString.doit3();
testString.doit4();
}
public void doit() {
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
System.out.println(e.getMethodName());
}
public void doit1() {
doit();
}
public void doit2() {
doit();
}
public void doit3() {
doit();
}
public void doit4() {
doit();
}
}
其他回答
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
class DBConnection {
String createdBy = null;
DBConnection(Throwable whoCreatedMe) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(os);
whoCreatedMe.printStackTrace(pw);
try {
createdBy = os.toString();
pw.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ThrowableTest {
public static void main(String[] args) {
Throwable createdBy = new Throwable(
"Connection created from DBConnectionManager");
DBConnection conn = new DBConnection(createdBy);
System.out.println(conn.createdBy);
}
}
OR
public static interface ICallback<T> { T doOperation(); }
public class TestCallerOfMethod {
public static <T> T callTwo(final ICallback<T> c){
// Pass the object created at callee to the caller
// From the passed object we can get; what is the callee name like below.
System.out.println(c.getClass().getEnclosingMethod().getName());
return c.doOperation();
}
public static boolean callOne(){
ICallback callBackInstance = new ICallback(Boolean){
@Override
public Boolean doOperation()
{
return true;
}
};
return callTwo(callBackInstance);
}
public static void main(String[] args) {
callOne();
}
}
Java 9 - JEP 259:栈遍历API
JEP 259为堆栈遍历提供了一个有效的标准API,允许对堆栈跟踪中的信息进行轻松过滤和延迟访问。在栈遍历API之前,访问栈帧的常见方法有:
的数组返回 包含类名和方法的StackTraceElement对象 每个堆栈跟踪元素的名称。 SecurityManager::getClassContext是一个受保护的方法 SecurityManager的子类来访问类上下文。 JDK-internal sun.reflect。Reflection::getCallerClass方法,你不应该使用它
使用这些api通常效率很低:
这些api要求VM急切地捕获整个快照 堆栈,它们返回表示整个堆栈的信息。 没有办法避免检查所有帧的代价,如果 调用者只对堆栈上的前几帧感兴趣。
为了找到直接调用者的类,首先获取一个StackWalker:
StackWalker walker = StackWalker
.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
然后调用getCallerClass():
Class<?> callerClass = walker.getCallerClass();
或者遍历StackFrame并获得前面的第一个StackFrame:
walker.walk(frames -> frames
.map(StackWalker.StackFrame::getDeclaringClass)
.skip(1)
.findFirst());
/**
* 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 = new Throwable().getStackTrace();
//System. out.println(ste[ste.length-depth].getClassName()+"#"+ste[ste.length-depth].getMethodName());
return ste[ste.length - depth].getMethodName();
}
例如,如果你试图获得用于调试目的的调用方法行,你需要通过编写这些静态方法的Utility类: (旧的java1.4代码,只是为了说明StackTraceElement的潜在用法)
/**
* Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils". <br />
* From the Stack Trace.
* @return "[class#method(line)]: " (never empty, first class past StackTraceUtils)
*/
public static String getClassMethodLine()
{
return getClassMethodLine(null);
}
/**
* Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils" and aclass. <br />
* Allows to get past a certain class.
* @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils.
* @return "[class#method(line)]: " (never empty, because if aclass is not found, returns first class past StackTraceUtils)
*/
public static String getClassMethodLine(final Class aclass)
{
final StackTraceElement st = getCallingStackTraceElement(aclass);
final String amsg = "[" + st.getClassName() + "#" + st.getMethodName() + "(" + st.getLineNumber()
+")] <" + Thread.currentThread().getName() + ">: ";
return amsg;
}
/**
* Returns the first stack trace element of the first class not equal to "StackTraceUtils" or "LogUtils" and aClass. <br />
* Stored in array of the callstack. <br />
* Allows to get past a certain class.
* @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils.
* @return stackTraceElement (never null, because if aClass is not found, returns first class past StackTraceUtils)
* @throws AssertionFailedException if resulting statckTrace is null (RuntimeException)
*/
public static StackTraceElement getCallingStackTraceElement(final Class aclass)
{
final Throwable t = new Throwable();
final StackTraceElement[] ste = t.getStackTrace();
int index = 1;
final int limit = ste.length;
StackTraceElement st = ste[index];
String className = st.getClassName();
boolean aclassfound = false;
if(aclass == null)
{
aclassfound = true;
}
StackTraceElement resst = null;
while(index < limit)
{
if(shouldExamine(className, aclass) == true)
{
if(resst == null)
{
resst = st;
}
if(aclassfound == true)
{
final StackTraceElement ast = onClassfound(aclass, className, st);
if(ast != null)
{
resst = ast;
break;
}
}
else
{
if(aclass != null && aclass.getName().equals(className) == true)
{
aclassfound = true;
}
}
}
index = index + 1;
st = ste[index];
className = st.getClassName();
}
if(resst == null)
{
//Assert.isNotNull(resst, "stack trace should null"); //NO OTHERWISE circular dependencies
throw new AssertionFailedException(StackTraceUtils.getClassMethodLine() + " null argument:" + "stack trace should null"); //$NON-NLS-1$
}
return resst;
}
static private boolean shouldExamine(String className, Class aclass)
{
final boolean res = StackTraceUtils.class.getName().equals(className) == false && (className.endsWith("LogUtils"
) == false || (aclass !=null && aclass.getName().endsWith("LogUtils")));
return res;
}
static private StackTraceElement onClassfound(Class aclass, String className, StackTraceElement st)
{
StackTraceElement resst = null;
if(aclass != null && aclass.getName().equals(className) == false)
{
resst = st;
}
if(aclass == null)
{
resst = st;
}
return resst;
}
使用方法:-
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
stackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
System.out.println(e.getMethodName());
方法示例代码的调用者在这里:-
public class TestString {
public static void main(String[] args) {
TestString testString = new TestString();
testString.doit1();
testString.doit2();
testString.doit3();
testString.doit4();
}
public void doit() {
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
System.out.println(e.getMethodName());
}
public void doit1() {
doit();
}
public void doit2() {
doit();
}
public void doit3() {
doit();
}
public void doit4() {
doit();
}
}
这个方法做同样的事情,但更简单一点,可能性能更好一点,在你使用反射的情况下,它会自动跳过那些帧。唯一的问题是它可能不会出现在非sun的jvm中,尽管它包含在JRockit 1.4—>1.6的运行时类中。(重点是,它不是一个公共类)。
sun.reflect.Reflection
/** Returns the class of the method <code>realFramesToSkip</code>
frames up the stack (zero-based), ignoring frames associated
with java.lang.reflect.Method.invoke() and its implementation.
The first frame is that associated with this method, so
<code>getCallerClass(0)</code> returns the Class object for
sun.reflect.Reflection. Frames associated with
java.lang.reflect.Method.invoke() and its implementation are
completely ignored and do not count toward the number of "real"
frames skipped. */
public static native Class getCallerClass(int realFramesToSkip);
至于realFramesToSkip的值应该是什么,Sun 1.5和1.6虚拟机版本的java.lang. lang. js。系统中,有一个名为getCallerClass()的包保护方法,它调用sun.reflect. reflect. getCallerClass(3),但在我的助手实用程序类中,我使用了4,因为有添加的助手类调用的帧。
推荐文章
- Java中的@UniqueConstraint注释
- 如何在清洁模式下运行eclipse ?如果我们这样做会发生什么?
- 获取java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory异常
- Java中的正则表达式命名组
- c#和Java的主要区别是什么?
- 什么是NullPointerException,我如何修复它?
- 在Java中使用“final”修饰符
- 无法在Flutter上找到捆绑的Java版本
- 如何在Kotlin解析JSON ?
- 如何在新的材质主题中改变背面箭头的颜色?
- 如何设置OkHttp连接超时
- 用于桌面应用程序的Swing vs JavaFx
- 为什么这个Java程序会终止,尽管它显然不应该(也没有)终止?
- 使用split("|")按管道符号拆分Java字符串
- 当内存不足导致抛出OutOfMemoryError时会发生什么?