如何在Java中获得调用者类
我想获得方法的调用者类,即
class foo{ bar(); }
在方法栏中,我需要获取类名foo
,并且我find了这个方法:
Class clazz = sun.reflect.Reflection.getCallerClass(1);
但是,即使getCallerClass
是public
,当我尝试调用它时,Eclipse会说:
访问限制:由于对所需库C:\ Program Files \ Java \ jre7 \ lib \ rt.jar的限制,不能访问types为Reflection的getCallerClass()方法
还有其他的select吗?
您可以生成堆栈跟踪并使用StackTraceElements中的信息。
例如,一个实用程序类可以返回您的调用类名称:
public class KDebug { public static String getCallerClassName() { StackTraceElement[] stElements = Thread.currentThread().getStackTrace(); for (int i=1; i<stElements.length; i++) { StackTraceElement ste = stElements[i]; if (!ste.getClassName().equals(KDebug.class.getName()) && ste.getClassName().indexOf("java.lang.Thread")!=0) { return ste.getClassName(); } } return null; } }
如果你从bar()
调用KDebug.getCallerClassName()
,你会得到"foo"
。
现在假设你想知道方法调用bar
的类(这更有趣,也许你真正想要的)。 你可以使用这个方法:
public static String getCallerCallerClassName() { StackTraceElement[] stElements = Thread.currentThread().getStackTrace(); String callerClassName = null; for (int i=1; i<stElements.length; i++) { StackTraceElement ste = stElements[i]; if (!ste.getClassName().equals(KDebug.class.getName())&& ste.getClassName().indexOf("java.lang.Thread")!=0) { if (callerClassName==null) { callerClassName = ste.getClassName(); } else if (!callerClassName.equals(ste.getClassName())) { return ste.getClassName(); } } } return null; }
这是为了debugging吗? 否则,可能会有更好的解决scheme来解决您的问题。
要获得调用者/被调用者类的名称使用下面的代码,它对我来说工作正常。
String callerClassName = new Exception().getStackTrace()[1].getClassName(); String calleeClassName = new Exception().getStackTrace()[0].getClassName();
这高度取决于你在找什么…但是这应该得到直接在这个对象中调用这个方法的类和方法。
- 索引0 =线程
- 索引1 =这个
- 索引2 =直接来电,可以自己。
- 索引3 … n =相互调用以获得索引2和以下的类和方法。
对于类/方法/文件名:
Thread.currentThread().getStackTrace()[2].getClassName(); Thread.currentThread().getStackTrace()[2].getMethodName(); Thread.currentThread().getStackTrace()[2].getFileName();
上课:
Class.forName(Thread.currentThread().getStackTrace()[2].getClassName())
FYI:Class.forName()抛出一个不是运行时的ClassNotFoundException。 你需要尝试抓住。
另外,如果你想忽略类中的调用,你必须添加一些逻辑循环来检查特定的事情。
就像…(我没有testing这段代码,所以要小心)
StackTraceElement[] stes = Thread.currentThread().getStackTrace(); for(int i=2;i<stes.length;i++) if(!stes[i].getClassName().equals(this.getClass().getName())) return stes[i].getClassName();
只是一个想法….
SecurityManager
有一个受保护的方法getClassContext
通过创build扩展SecurityManager的实用程序类,您可以访问它。
public class CallingClass extends SecurityManager { public static final CallingClass INSTANCE = new CallingClass(); public Class[] getCallingClasses() { return getClassContext(); } }
使用CallingClass.INSTANCE.getCallingClasses()
来检索调用类。
还有一个小图书馆(免责声明:我的) WhoCalled哪个公开这个信息。 它在可用时使用Reflection.getCallerClass,否则返回到SecurityManager。
我知道这是一个老问题,但我相信提问者想要的是class级,而不是class级名称。 我写了一个方法来获得实际的课程。 这是一种微妙的,可能并不总是工作,但有时当你需要实际的类,你将不得不使用这种方法…
/** * Get the caller class. * @param level The level of the caller class. * For example: If you are calling this class inside a method and you want to get the caller class of that method, * you would use level 2. If you want the caller of that class, you would use level 3. * * Usually level 2 is the one you want. * @return The caller class. * @throws ClassNotFoundException We failed to find the caller class. */ public static Class getCallerClass(int level) throws ClassNotFoundException { StackTraceElement[] stElements = Thread.currentThread().getStackTrace(); String rawFQN = stElements[level+1].toString().split("\\(")[0]; return Class.forName(rawFQN.substring(0, rawFQN.lastIndexOf('.'))); }
这是获取调用者类最有效的方法。 其他方法需要整个堆栈转储,只给你类名。
但是,这个课程在sun.*
下sun.*
这是真正的内部使用。 这意味着它可能无法在其他Java平台或其他Java版本上运行。 你必须决定这是否是一个问题。
OP正在遇到的错误消息只是一个Eclipsefunction。 如果你愿意将你的代码绑定到特定的制造商(甚至是版本)的JVM,你可以有效地使用方法sun.reflect.Reflection.getCallerClass()
。 然后,您可以编译Eclipse之外的代码,或者将其configuration为不将此诊断视为错误。
最糟糕的Eclipseconfiguration是通过以下方式禁用所有发生的错误:
Project Properties
/ Java Compiler
/ Errors/Warnings
/ Enable project specific settings
设置为选中/ Deprecated and restrited API
/ Forbidden reference (access rules)
设置为Warning
或Ignore
。
更好的Eclipseconfiguration是通过以下方式禁用特定的错误:
Project Properties
/ Java Build Path
/ Libraries
/ JRE System Library
展开/ Access rules:
select/ Edit...
/ Add...
/ Resolution:
设置为Discouraged
或Accessible
/ Rule Pattern
设置为sun/reflect/Reflection
。
我正在使用以下方法从堆栈跟踪中获取特定类的调用方:
package test.log; public class CallerClassTest { public static void main(final String[] args) { final Caller caller = new Caller(new Callee()); caller.execute(); } private static class Caller { private final Callee c; public Caller(final Callee c) { this.c = c; } void execute() { c.call(); } } static class Callee { void call() { System.out.println(getCallerClassName(this.getClass())); } } /** * Searches the current threads stacktrace for the class that called the given class. Returns {@code null} if the * calling class could not be found. * * @param clazz * the class that has been called * * @return the caller that called the class or {@code null} */ public static String getCallerClassName(final Class<?> clazz) { final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); final String className = clazz.getName(); boolean classFound = false; for (int i = 1; i < stackTrace.length; i++) { final StackTraceElement element = stackTrace[i]; final String callerClassName = element.getClassName(); // check if class name is the requested class if (callerClassName.equals(className)) classFound = true; else if (classFound) return callerClassName; } return null; } }
由于我现在有同样的问题,这就是我所做的:
-
我更喜欢com.sun.Reflection而不是stackTrace,因为堆栈跟踪只产生名称而不是类(包括类加载器)本身。
-
该方法已被弃用,但仍在Java 8 SDK中。
//方法描述符#124(I)Ljava / lang / Class; (不赞成使用)//签名:(I)Ljava / lang / Class <*>; @ java.lang.Deprecated public static native java.lang.Class getCallerClass(int arg0);
- 没有int参数的方法不被弃用
//方法描述符#122()Ljava / lang / Class; //签名:()Ljava / lang / Class <*>; @ sun.reflect.CallerSensitive public static native java.lang.Class getCallerClass();
由于我必须是平台独立的,包括安全限制,所以我只是创build一个灵活的方法:
-
检查com.sun.Reflection是否可用(安全例外禁用此机制)
-
如果1是肯定的,那么用int或no int参数来获取方法。
-
如果2是,则调用它。
如果没有达到3.我使用堆栈跟踪返回名称。 我使用了一个特殊的结果对象,它包含了类或者string,这个对象告诉了它是什么以及为什么。
[摘要]我使用stacktrace进行备份,并绕过eclipse编译器警告我使用reflection。 工作非常好。 保持代码清洁,像一个魅力工作,也说明了正确涉及的问题。
我用了很长时间,今天我search了一个相关的问题
查找下面的一个简单的例子,说明如何获得类和方法名称。
public static void main(String args[]) { callMe(); } void callMe() { try { throw new Exception("Who called me?"); } catch( Exception e ) { System.out.println( "I was called by " + e.getStackTrace()[1].getClassName() + "." + e.getStackTrace()[1].getMethodName() + "()!" ); } }
e有getClassName()
, getFileName()
, getLineNumber()
和getMethodName()
…