当前位置: 移动技术网 > IT编程>开发语言>Java > Java反射之Call stack introspection详解

Java反射之Call stack introspection详解

2019年07月19日  | 移动技术网IT编程  | 我要评论

java是基于栈设计的语言,其实与c、c++语言相同。整个程序的运行表现在方法的执行是一系列入栈出栈的行为,栈是线程私有的。

在java语言中,我们可以跟踪方法的调用关系,即当前栈帧(栈顶)和已经入栈的栈帧的层次关系。

从java1.4以后,java语言的throwable类提供了以下方法:

opendeclarationstacktraceelement[]java.lang.throwable.getstacktrace()
providesprogrammaticaccesstothestacktraceinformationprintedbyprintstacktrace().returnsanarrayofstacktraceelements,eachrepresentingonestackframe.thezerothelementofthearray(assumingthearray'slengthisnon-zero)representsthetopofthestack,whichisthelastmethodinvocationinthesequence.typically,thisisthepointatwhichthisthrowablewascreatedandthrown.thelastelementofthearray(assumingthearray'slengthisnon-zero)representsthebottomofthestack,whichisthefirstmethodinvocationinthesequence.
somevirtualmachinesmay,undersomecircumstances,omitoneormorestackframesfromthestacktrace.intheextremecase,avirtualmachinethathasnostacktraceinformationconcerningthisthrowableispermittedtoreturnazero-lengtharrayfromthismethod.generallyspeaking,thearrayreturnedbythismethodwillcontainoneelementforeveryframethatwouldbeprintedbyprintstacktrace.writestothereturnedarraydonotaffectfuturecallstothismethod.
returns:
anarrayofstacktraceelementsrepresentingthestacktracepertainingtothisthrowable.
since:
1.4

该方法返回的stacktraceelement[] 就是栈帧数组。数组下标0的元素代表当前栈顶栈帧,数组的最大下标代表调用栈序列中第一个栈帧,也就是第一个方法的调用。我们可以从stacktraceelement得到栈调用层级的关系、调用方法名及调用入口位置,代码示例:

执行结果:

调用结果显示的方法调用层级关系。

那我们得到这些信息有什么用呢。

1.日志:这些信息可以让应用的日志系统得到信息更详细。

2.安全:api可以决定调用者当前包或者类是否有权限进入。

3.流程控制:可以避免一些流程错误,比如无限递归调用。

实现一个简单的日志系统:

package com.doctor.reflect;
import java.io.printwriter;
import java.io.stringwriter;
/**
 * call stack introspection
 * 
 * @author sdcuike
 *
 *     created at 2016年8月29日 下午9:40:35
 */
public class callstackintrospectiondemo {
	private static final mylogger logger = new loggerimpl();
	public static void main(string[] args) {
		logger.logrecord("hello");
		illegalargumentexception exception = new illegalargumentexception("illegalargumentexception");
		logger.logproblem("throwable", exception);
	}
	public interface mylogger {
		// types for log records
		int error  = 0;
		int warning = 100;
		int status = 200;
		int debug  = 300;
		int trace  = 400;
		void logrecord(string message);
		void logproblem(string message, throwable throwable);
	}
	public static class loggerimpl implements mylogger {
		@override
		    public void logrecord(string message) {
			throwable throwable = new throwable();
			log(message, throwable.getstacktrace()[1]);
		}
		@override
		    public void logproblem(string message, throwable throwable) {
			stringwriter out = new stringwriter();
			printwriter writer = new printwriter(out);
			throwable.printstacktrace(writer);
			writer.flush();
			log(message + out.tostring(), throwable.getstacktrace()[0]);
		}
		private void log(string message, stacktraceelement stacktraceelement) {
			string classname = stacktraceelement.getclassname();
			string methodname = stacktraceelement.getmethodname();
			int linenumber = stacktraceelement.getlinenumber();
			system.out.println(string.join(" ", "模拟打印日志:", methodname, classname, "" + linenumber, message));
		}
	}
}

执行结果:

模拟打印日志: main com.doctor.reflect.callstackintrospectiondemo 36 hello
模拟打印日志: main com.doctor.reflect.callstackintrospectiondemo 38 throwablejava.lang.illegalargumentexception: illegalargumentexception
  at com.doctor.reflect.callstackintrospectiondemo.main(callstackintrospectiondemo.java:38)

上述日志,只是简单的在控制台打印一些信息。

总结

以上就是本文关于java反射之call stack introspection详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:

java反射简易教程

关于java反射机制 你需要知道的事情

java的rtti和反射机制代码分析

如有不足之处,欢迎留言指出。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网