查找从何处加载Java类


184

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

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

那么,如何让类加载器告诉我实际的类文件来自磁盘上的什么地方?

编辑:如果类加载器由于版本不匹配(或其他原因)而实际上无法加载该类,该如何在读取它之前找出我们要读取的文件呢?


4
@JarrodRoberson我不认为这应该被认为是重复的 stackoverflow.com/questions/11747833/... 因为这个问题被要求在2008年和问题针对2012
卢克

Answers:


188

这是一个例子:

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

32
为了减少多余的输入,还可以使用较短的版本:Test.class.getResource("Test.class"),它不会重复软件包名称。
meriton

1
如果该类是编译的,例如从.groovy文件中编译,该怎么办?
OndraŽižka2013年

35
@meriton:或者,为了在refactorinsgs中生存:Test.class.getResource(Test.class.getSimpleName() + ".class")
leonbloy

1
对于BouncyCastleProvider完整的包名但是是必需的。
帕维尔·弗拉索夫

3
有可能getClassLoader()返回null。请参见此处以获取此方法的扩展以处理该问题。
OldCurmudgeon 2014年

100

查找从何处加载类的另一种方法(不处理源代码)是使用以下选项启动Java VM: -verbose:class


6
这工作得很好,并且不存在使用null ClassLoader处理类的问题
lexicalscope

2
@ries如果不需要以编程方式执行此操作,则绝对是一种方法,它确实解决了我的问题。但是,OP特别询问了如何以编程方式执行此操作。
SantiBailors

80
getClass().getProtectionDomain().getCodeSource().getLocation();

4
是的,尽管它不能与安装的安全管理器一起使用并且没有必需的权限。
汤姆·哈特芬

1
仅供参考,NPE =空指针异常。HTH!
Evgeni Sergeev

只要可以引用实例,则首选此方法,因为您可以从两个不同的位置加载同一类。
米格尔·平

1
当从Java 9+模块中调用时,它也不起作用(当然,您在2008年还无法知道)。
杰夫·G

28

这是我们使用的:

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

这将根据ClassLoader实现而起作用: getClass().getProtectionDomain().getCodeSource().getLocation()


17

当对象的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";
}

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/

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


3

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

        String className = MyClass.class.getName().replace(".", "/")+".class";
        URL classUrl  = MyClass.class.getClassLoader().getResource(className);
        String fullPath = classUrl==null ? null : classUrl.getPath();

需要为:URL classUrl = MyClass.class.getClassLoader()。getResource(“ /” + className);
Andrew Coates

MyClass.class是重要的部分-getClass()可以返回Proxy!然后,您可以获得类似MyClass $$ EnhancerBySpringCGLIB $$ a98db882.class的名称,以及空URL。
jalmasi


1

简单方法:

System.out.println(java.lang.String.class.getResource(String.class.getSimpleName()+“。class”)));

输出示例:

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

要么

字符串obj =“简单测试”; System.out.println(obj.getClass()。getResource(obj.getClass()。getSimpleName()+“。class”)));

输出示例:

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


0

此方法适用于文件和jar:

Class clazz = Class.forName(nameOfClassYouWant);

URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".", "/") + ".class");
InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish

-1

假设您正在使用名为的类MyClass,则应该可以进行以下操作:

MyClass.class.getClassLoader();

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


这将返回用于加载类的ClassLoader,不是吗?它找不到.class文件在哪里?
Koray Tugay 2014年

1
不,不是。实际上,类加载器可以引用完全不同的类路径-这意味着它将完全无法获取实际的类位置。
托马什Zato -恢复莫妮卡
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.