我想得到该方法的调用者类,即
class foo{
bar();
}
在方法栏中,我需要获取类名foo
,我找到了这个方法:
Class clazz = sun.reflect.Reflection.getCallerClass(1);
但是,即使getCallerClass
是public
,当我尝试调用它时,Eclipse会说:
访问限制:来自类型的方法getCallerClass() 由于对所需库的限制,无法访问反射 C:\ Program Files \ Java \ jre7 \ lib \ rt.jar
还有其他选择吗?
答案 0 :(得分:84)
您可以生成堆栈跟踪并使用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;
}
}
如果您从KDebug.getCallerClassName()
致电bar()
,您将获得"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;
}
是调试吗?如果没有,可能会有更好的解决方案来解决您的问题。
答案 1 :(得分:31)
要使用以下代码获取调用者/被调用者类名称,它对我来说很好。
String callerClassName = new Exception().getStackTrace()[1].getClassName();
String calleeClassName = new Exception().getStackTrace()[0].getClassName();
答案 2 :(得分:22)
这高度取决于你要找的东西...但是这应该得到直接在这个对象中调用这个方法的类和方法。
对于班级/方法/文件名:
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。你需要尝试捕获。
另外,如果你想忽略类本身内的调用,你必须添加一些带逻辑的循环来检查那个特定的东西。
类似......(我没有测试过这段代码所以要小心)
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();
只是一个想法......
答案 3 :(得分:11)
SecurityManager
有一个受保护的方法getClassContext
通过创建扩展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。
答案 4 :(得分:5)
我知道这是一个古老的问题,但我相信提问者想要的是班级,而不是班级名称。我写了一个小方法来获得实际的课程。它有点像学习,可能并不总是有效,但有时当你需要实际的课时,你将不得不使用这种方法......
/**
* 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('.')));
}
答案 5 :(得分:3)
这是获得调用者类的最有效方法。其他方法采用整个堆栈转储,只为您提供类名。
然而,这个类在sun.*
下面,真正供内部使用。这意味着它可能无法在其他Java平台甚至其他Java版本上运行。你必须决定这是否是一个问题。
答案 6 :(得分:2)
OP遇到的错误消息只是一个Eclipse功能。如果您愿意将代码绑定到JVM的特定制造商(甚至版本),则可以有效地使用方法sun.reflect.Reflection.getCallerClass()
。然后,您可以在Eclipse之外编译代码,或者将其配置为不将此诊断视为错误。
更糟糕的Eclipse配置是通过以下方式禁用所有错误:
Project Properties
/ Java Compiler
/ Errors/Warnings
/ Enable project specific settings
设置为已选中/ Deprecated and restrited API
/ Forbidden reference (access rules)
设置为Warning
或{ {1}}。
更好的Eclipse配置是通过以下方式禁用特定的错误:
Ignore
/ Project Properties
/ Java Build Path
/ Libraries
展开/ JRE System Library
选择/ Access rules:
/ Edit...
/ {{1设置为Add...
或Resolution:
/ Discouraged
设置为Accessible
。
答案 7 :(得分:1)
我使用以下方法从stacktrace获取特定类的调用者:
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;
}
}
答案 8 :(得分:0)
在下面找到一个简单的示例,说明如何获取类和方法名称。
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()
......
答案 9 :(得分:0)
由于我目前遇到的问题与此相同:
我更喜欢com.sun.Reflection而不是stackTrace,因为堆栈跟踪只生成名称而不是类(包括类加载器)本身。
该方法已弃用,但仍在Java 8 SDK中。
//方法描述符#124(I)Ljava / lang / Class; (废弃) //签名:(I)Ljava / lang / Class&lt; *&gt ;; @ java.lang.Deprecated public static native java.lang.Class getCallerClass(int arg0);
//方法描述符#122()Ljava / lang / Class; //签名:()Ljava / lang / Class&lt; *&gt ;; @ sun.reflect.CallerSensitive public static native java.lang.Class getCallerClass();
由于我必须是平台无关的bla bla,包括安全限制,我只是创建一个灵活的方法:
检查com.sun.Reflection是否可用(安全例外禁用此机制)
如果1为yes,则使用int或no int参数获取方法。
如果2是,请调用它。
如果从未达到过3.我使用堆栈跟踪返回名称。我使用一个包含类或字符串的特殊结果对象,该对象确切地告诉它是什么以及为什么。
[总结] 我使用stacktrace进行备份并绕过eclipse编译器警告我使用反射。效果很好。保持代码清洁,像魅力一样工作,并正确地说明问题。
我用了很长时间,今天我搜索了一个相关的问题,所以