静态方法获取调用类

本文介绍如何使用Java的Throwable类获取堆栈信息,通过分析StackTraceElement对象来确定调用静态方法的上下文,从而解决静态方法调用跟踪的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景

    静态方法,必然是总集办法。

    比如工厂类?公共的静态方法?比如打印日志什么的。

    静态方法共有的一个特性,那就是提供方法给别人调用,且十分方便(抛开静态的开销的话)。

    但是,唯一的弊端就是不由自主。因为调用的地方很多,静态方法很难做到自己的上下文管理。

    比如打印日志,打在外面吧,没有详细信息,打在内部吧,又不知道谁调用了。

    逻辑的具体实现不是问题了,但是,究竟是谁用了,谁动了我的奶罩。

 

stack

    数据结构都知道堆栈,程序执行都离不开堆栈。

    如果说我们很熟悉堆栈,那像是无稽之谈,不过如果经常调bug,那你可以说你很常接触堆栈了。

    为什么,因为exception啊

    为什么要说堆栈,为什么要炫耀着刺眼的血红?

    因为真有用啊。

    全部的Exception的顶层,那必然是Object(废话),但是,从有分类开始,它的始祖是Throwable。

    这里面就有堆栈信息,为了抛出异常,它是已经记录堆栈了的,这个可以为我所用。

 

测试

first

package com.godme.stack;

public class First {
	public static void test(){
		StackTraceElement[] stack = new Throwable().getStackTrace();
		StringBuffer sb = new StringBuffer();
		for(StackTraceElement element:stack){
			sb.delete(0, sb.length());
			sb.append("file\t:\t" + element.getFileName() + "\n");
			sb.append("class\t:\t" + element.getClassName() + "\n");
			sb.append("line\t:\t" + element.getLineNumber() + "\n");
			sb.append("method\t:\t" + element.getMethodName());
			System.out.println(sb.toString());
			System.out.println("========================================");
		}
	}
}

second

package com.godme.stack;

public class Second {
	public static void test(){
		First.test();
	}
}

third

package com.godme.stack;

public class Third {
	public static void test(){
		Second.test();
	}
}

fourth

package com.godme.stack;

public class Fourth {
	public static void test(){
		Third.test();
	}
}

fifth

package com.godme.stack;

public class Fifth {
	public static void test(){
		Fourth.test();
	}
}

好吧,我很蛋疼,接下来是主菜

package com.godme.stack;

public class Main {
	public static void main(String[] args) {
		Fifth.test();
	}
}

执行结果如下

file	:	First.java
class	:	com.godme.stack.First
line	:	5
method	:	test
========================================
file	:	Second.java
class	:	com.godme.stack.Second
line	:	5
method	:	test
========================================
file	:	Third.java
class	:	com.godme.stack.Third
line	:	5
method	:	test
========================================
file	:	Fourth.java
class	:	com.godme.stack.Fourth
line	:	5
method	:	test
========================================
file	:	Fifth.java
class	:	com.godme.stack.Fifth
line	:	5
method	:	test
========================================
file	:	Main.java
class	:	com.godme.stack.Main
line	:	5
method	:	main
========================================

从下往上看,可以观察到java的压栈顺序。

分别是从调用顺序进行压栈:main>5>4>3>2>1

不过,Throwable记录的好像是出栈顺序,因为先进后出,所以看起来first的索引还会在前。

 

回到最初的想法:想知道谁在调用了静态方法。

不就是静态方法的上一个压栈么。方法得到执行,必然在出栈顺序的首位,索引为0。

那调用该方法的"东西",就在index=1的栈顶老二的位置了。

复验

first

package com.godme.stack;

public class First {
	public static void test(){
		StackTraceElement stack = new Throwable().getStackTrace()[1];
		StringBuffer sb = new StringBuffer();
			sb.delete(0, sb.length());
			sb.append("file\t:\t" + stack.getFileName() + "\n");
			sb.append("class\t:\t" + stack.getClassName() + "\n");
			sb.append("line\t:\t" + stack.getLineNumber() + "\n");
			sb.append("method\t:\t" + stack.getMethodName());
			System.out.println(sb.toString());
			System.out.println("=================================");
	}
}

second

package com.godme.stack;

public class Second {
	public static void test(){
		First.test();
	}
}

third

package com.godme.stack;

public class Third {
	public static void test(){
		First.test();
	}
}

fourth

package com.godme.stack;

public class Fourth {
	public static void test(){
		First.test();
	}
}

fifth

package com.godme.stack;

public class Fifth {
	public static void test(){
		First.test();
	}
}

嗯,启动

package com.godme.stack;

public class Main {
	public static void main(String[] args) {
		First.test();
		Second.test();
		Third.test();
		Fourth.test();
		Fifth.test();
	}
}

结果

file	:	Main.java
class	:	com.godme.stack.Main
line	:	5
method	:	main
=================================
file	:	Second.java
class	:	com.godme.stack.Second
line	:	5
method	:	test
=================================
file	:	Third.java
class	:	com.godme.stack.Third
line	:	5
method	:	test
=================================
file	:	Fourth.java
class	:	com.godme.stack.Fourth
line	:	5
method	:	test
=================================
file	:	Fifth.java
class	:	com.godme.stack.Fifth
line	:	5
method	:	test
=================================

嗯,和理论一致了,这样就能够知道究竟是谁动了我的XX了。

有必要的话,可以研究一下StackTraceElement,还想有啥操作的话,不是可以getClass么。

反正一路上的家伙都记录在册,想做什么,自己开心啦。

简单一句即可完成

package com.godme.stack;

public class First {
	public static void test(){
		StackTraceElement stack = new Throwable().getStackTrace()[1];
		StringBuffer sb = new StringBuffer();
			sb.delete(0, sb.length());
			sb.append("file\t:\t" + stack.getFileName() + "\n");
			sb.append("class\t:\t" + stack.getClassName() + "\n");
			sb.append("line\t:\t" + stack.getLineNumber() + "\n");
			sb.append("method\t:\t" + stack.getMethodName());
			System.out.println(sb.toString());
			System.out.println("=================================");
	}
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值