206

有谁知道如何以编程方式找出java类加载器实际从哪里加载类?

我经常在大型项目中工作,其中类路径变得很长,手动搜索并不是一个真正的选择。我最近遇到了一个问题,即类加载器加载了一个不正确的类版本,因为它位于两个不同位置的类路径上。

那么如何让类加载器告诉我实际的类文件来自磁盘的哪个位置?

编辑:如果类加载器由于版本不匹配(或其他原因)实际上无法加载类怎么办,无论如何我们可以在读取它之前找出它试图读取的文件吗?

4

11 回答 11

205

这是一个例子:

package foo;

public class Test
{
    public static void main(String[] args)
    {
        ClassLoader loader = Test.class.getClassLoader();
        System.out.println(loader.getResource("foo/Test.class"));
    }
}

这打印出来:

file:/C:/Users/Jon/Test/foo/Test.class
于 2008-10-22T21:15:09.013 回答
107

另一种找出类从哪里加载(不操作源)的方法是使用以下选项启动 Java VM:-verbose:class

于 2008-10-23T07:16:01.980 回答
92
getClass().getProtectionDomain().getCodeSource().getLocation();
于 2008-10-22T21:39:59.837 回答
28

这就是我们使用的:

public static String getClassResource(Class<?> klass) {
  return klass.getClassLoader().getResource(
     klass.getName().replace('.', '/') + ".class").toString();
}

这将取决于 ClassLoader 实现: getClass().getProtectionDomain().getCodeSource().getLocation()

于 2008-10-22T21:53:58.637 回答
20

ClassLoader当对象被注册时,Jon 的版本失败,null这似乎暗示它是由 Boot 加载的ClassLoader

此方法处理该问题:

public static String whereFrom(Object o) {
  if ( o == null ) {
    return null;
  }
  Class<?> c = o.getClass();
  ClassLoader loader = c.getClassLoader();
  if ( loader == null ) {
    // Try the bootstrap classloader - obtained from the ultimate parent of the System Class Loader.
    loader = ClassLoader.getSystemClassLoader();
    while ( loader != null && loader.getParent() != null ) {
      loader = loader.getParent();
    }
  }
  if (loader != null) {
    String name = c.getCanonicalName();
    URL resource = loader.getResource(name.replace(".", "/") + ".class");
    if ( resource != null ) {
      return resource.toString();
    }
  }
  return "Unknown";
}
于 2013-10-21T12:10:20.690 回答
5

仅编辑第一行:Main.class

Class<?> c = Main.class;
String path = c.getResource(c.getSimpleName() + ".class").getPath().replace(c.getSimpleName() + ".class", "");

System.out.println(path);

输出:

/C:/Users/Test/bin/

也许风格不好,但效果很好!

于 2015-04-22T15:49:31.250 回答
3

通常,我们不使用硬编码。我们可以先获取className,然后使用ClassLoader获取class URL。

        String className = MyClass.class.getName().replace(".", "/")+".class";
        URL classUrl  = MyClass.class.getClassLoader().getResource(className);
        String fullPath = classUrl==null ? null : classUrl.getPath();
于 2017-10-20T19:46:05.053 回答
1

看看这个类似的问题。 发现同一类的工具..

我认为最相关的障碍是您是否有自定义类加载器(从 db 或 ldap 加载)

于 2008-10-22T20:49:18.533 回答
1

简单的方法:

System.out.println(java.lang.String.class.getResource(String.class.getSimpleName()+".class"));

输出示例:

jar:file:/D:/Java/jdk1.8/jre/lib/rt.jar!/java/lang/String.class

或者

String obj = "简单测试"; System.out.println(obj.getClass().getResource(obj.getClass().getSimpleName()+".class"));

输出示例:

jar:file:/D:/Java/jdk1.8/jre/lib/rt.jar!/java/lang/String.class

于 2020-02-07T20:27:25.247 回答
0

这种方法适用于文件和罐子:

Class clazz = Class.forName(nameOfClassYouWant);

URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".", "/") + ".class");
InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish
于 2017-02-14T23:48:56.150 回答
-1

假设您正在使用名为 的类MyClass,则以下内容应该有效:

MyClass.class.getClassLoader();

能否获得 .class 文件的磁盘位置取决于类加载器本身。例如,如果您使用 BCEL 之类的东西,则某个类甚至可能没有磁盘表示。

于 2008-10-22T20:46:37.167 回答