从Java代码中查找主类名称的便携式方法

3

有没有办法从任意在当前JVM中运行的代码中找到用于启动当前JVM的主类的名称?

所谓任意,是指该代码不一定在主线程中运行,或者可能在main被调用之前就在主线程中运行(例如,用户提供的java.system.classloader中的代码,在main之前运行,因为它用于加载main)- 因此无法检查调用堆栈。


在JVM上,主类的主方法首先被调用。(参见http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.1)所以,“可能在main方法被调用之前就在主线程中运行”是什么意思?我认为这个短语提到了“静态初始化程序”或“Thread#run()”。 - cocoatomo
@cocoatomo:我漏掉了什么。那个链接是否展示了原帖提出的问题的解决方案?即使我已经看过了,但不知道为何还是错过了。 - Hovercraft Full Of Eels
@Hovercraft Full Of Eels:抱歉,我在评论之前误按了回车键。我想要理解BeeOnRope的意图,因此我将确保符合BeeOnRope所希望达到的条件。 - cocoatomo
虽然JLS可能会这样说,但在实践中并不是这样的。主类必须由ClassLoader加载,而该ClassLoader本身就是一个对象,其类必须在main之前加载。典型的ClassLoader实现,如URLClassLoader,在其实现中将使用大量其他类,这些类也将在main之前加载。如果您编写自己的ClassLoader并通过指定java.system.class.loader属性将其安装为系统ClassLoader,则可以轻松地看到这一点。 - BeeOnRope
1个回答

8

这是我能提供的最接近解决方案,你可以从这里开始。我不能保证它是真正可移植的,如果任何方法调用另一个类的主方法,它将无法工作。如果你找到更简洁的解决方案,请告诉我。

import java.util.Map.Entry;

public class TestMain {

    /**
     * @param args
     * @throws ClassNotFoundException 
     */
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println(findMainClass());
    }

    public static String findMainClass() throws ClassNotFoundException{
        for (Entry<Thread, StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet()) {
            Thread thread = entry.getKey();
            if (thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals("main")) {
                for (StackTraceElement stackTraceElement : entry.getValue()) {
                    if (stackTraceElement.getMethodName().equals("main")) {

                        try {
                            Class<?> c = Class.forName(stackTraceElement.getClassName());
                            Class[] argTypes = new Class[] { String[].class };
                            //This will throw NoSuchMethodException in case of fake main methods
                            c.getDeclaredMethod("main", argTypes);
                            return stackTraceElement.getClassName();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }
}

谢谢,我知道这种方法,但不幸的是它对我不起作用,因为它还需要在包含main方法的类被加载之前就能工作(请参见我添加到类加载器问题的评论)。 - BeeOnRope
尽管这样做是正确的,而且如果愿意推迟基于主类需要执行的工作,我仍然会接受它。 - BeeOnRope
顺便提一下,如果你想要避免更多的误报,我认为你可以查看调用main函数的类,并验证它是否是预期的JDK特定类 - 虽然这会引入对特定JDK或JDK的依赖。 - BeeOnRope

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接