如何在Java中获得调用者类

我想获得方法的调用者类,即

class foo{ bar(); } 

在方法栏中,我需要获取类名foo ,并且我find了这个方法:

 Class clazz = sun.reflect.Reflection.getCallerClass(1); 

但是,即使getCallerClasspublic ,当我尝试调用它时,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)设置为WarningIgnore

更好的Eclipseconfiguration是通过以下方式禁用特定的错误:

Project Properties / Java Build Path / Libraries / JRE System Library展开/ Access rules:select/ Edit... / Add... / Resolution:设置为DiscouragedAccessible / 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; } } 

由于我现在有同样的问题,这就是我所做的:

  1. 我更喜欢com.sun.Reflection而不是stackTrace,因为堆栈跟踪只产生名称而不是类(包括类加载器)本身。

  2. 该方法已被弃用,但仍在Java 8 SDK中。

//方法描述符#124(I)Ljava / lang / Class; (不赞成使用)//签名:(I)Ljava / lang / Class <*>; @ java.lang.Deprecated public static native java.lang.Class getCallerClass(int arg0);

  1. 没有int参数的方法不被弃用

//方法描述符#122()Ljava / lang / Class; //签名:()Ljava / lang / Class <*>; @ sun.reflect.CallerSensitive public static native java.lang.Class getCallerClass();

由于我必须是平台独立的,包括安全限制,所以我只是创build一个灵活的方法:

  1. 检查com.sun.Reflection是否可用(安全例外禁用此机制)

  2. 如果1是肯定的,那么用int或no int参数来获取方法。

  3. 如果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()