查找从何处加载java类
有人知道如何通过编程找出java类装入器实际从何处装入类吗 我经常在大型项目中工作,在这些项目中,类路径变得非常长,手动搜索实际上不是一种选择。我最近遇到了一个问题,类加载器加载了一个不正确的类版本,因为它位于两个不同位置的类路径上 那么,如何让类加载器告诉我实际的类文件来自磁盘上的什么地方呢查找从何处加载java类,java,classpath,classloader,Java,Classpath,Classloader,有人知道如何通过编程找出java类装入器实际从何处装入类吗 我经常在大型项目中工作,在这些项目中,类路径变得非常长,手动搜索实际上不是一种选择。我最近遇到了一个问题,类加载器加载了一个不正确的类版本,因为它位于两个不同位置的类路径上 那么,如何让类加载器告诉我实际的类文件来自磁盘上的什么地方呢 编辑:如果类加载器由于版本不匹配(或其他原因)而无法加载该类,那么我们是否可以在读取该类之前找出该类试图读取的文件?假设您使用的是名为MyClass的类,则以下操作应该有效: MyClass.class.
编辑:如果类加载器由于版本不匹配(或其他原因)而无法加载该类,那么我们是否可以在读取该类之前找出该类试图读取的文件?假设您使用的是名为
MyClass
的类,则以下操作应该有效:
MyClass.class.getClassLoader();
能否获取.class文件的磁盘位置取决于类加载器本身。例如,如果您正在使用类似BCEL的东西,某个类甚至可能没有磁盘上的表示形式。看看这个类似的问题。 我认为最相关的障碍是如果您有一个自定义类加载器(从db或ldap加载)这里有一个示例:
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
这就是我们所使用的:
public static String getClassResource(Class<?> klass) {
return klass.getClassLoader().getResource(
klass.getName().replace('.', '/') + ".class").toString();
}
公共静态字符串getClassResource(类klass){
返回klass.getClassLoader().getResource(
klass.getName().replace('.','/')+“.class”).toString();
}
这取决于类加载器实现:
getClass().getProtectionDomain().getCodeSource().getLocation()
找到类从何处加载的另一种方法(无需操作源)是使用以下选项启动Java VM:-verbose:class当对象的ClassLoader
注册为null
时,Jon的版本失败,这似乎意味着它是由引导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";
}
公共静态字符串(对象o){
如果(o==null){
返回null;
}
c类=o.getClass();
ClassLoader=c.getClassLoader();
if(loader==null){
//尝试引导类加载器-从系统类加载器的最终父级获得。
loader=ClassLoader.getSystemClassLoader();
while(loader!=null&&loader.getParent()!=null){
loader=loader.getParent();
}
}
if(加载程序!=null){
String name=c.getCanonicalName();
URL resource=loader.getResource(name.replace(“.”,“/”)+“.class”);
if(资源!=null){
返回resource.toString();
}
}
返回“未知”;
}
只编辑第一行:Main
.class
Class<?> c = Main.class;
String path = c.getResource(c.getSimpleName() + ".class").getPath().replace(c.getSimpleName() + ".class", "");
System.out.println(path);
也许是糟糕的风格,但很好 此方法适用于文件和JAR:
Class clazz = Class.forName(nameOfClassYouWant);
URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".", "/") + ".class");
InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish
通常,我们不知道如何使用硬编码。我们可以先获取className,然后使用ClassLoader获取类URL
String className = MyClass.class.getName().replace(".", "/")+".class";
URL classUrl = MyClass.class.getClassLoader().getResource(className);
String fullPath = classUrl==null ? null : classUrl.getPath();
简单方法:
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
是的,尽管它不能与安装的安全管理器一起工作,并且没有所需的权限。仅供参考,NPE=Null指针异常。嗯!只要你有一个实例的引用,这个方法是首选的,因为你可以从两个不同的位置加载同一个类。当从Java 9+模块调用时,这个方法也不起作用(当然,你在2008年不可能知道)。这个方法工作得很好,并且不存在处理null类的问题ClassLoader@ries如果一个人不需要以编程的方式来做这件事,那么这绝对是一条路,它确实解决了我的问题。然而,OP明确提出了如何通过编程实现这一点。为了减少冗余类型,还可以使用较短的版本:Test.class.getResource(“Test.class”)
,该版本不重复包名。如果该类是编译的,例如从.groovy文件编译的,该怎么办?@meriton:Or,要在重构中生存:Test.class.getResource(Test.class.getSimpleName()+“.class”)
ForBouncyCastleProvider
需要完整的包名。getClassLoader()
可能返回null
。有关此方法的扩展,请参阅。这将返回用于加载类的类加载器,不是吗?它找不到.class文件的位置?不,找不到。类加载器实际上可以引用到完全不同的类路径-这意味着它将完全无法读取实际的类位置。需要是:URL classUrl=MyClass.class.getClassLoader().getResource(“/”+className);类是重要的部分-getClass()可以返回代理!然后,您可以获得MyClass$$EnhancerBySpringCGLIB$$a98db882.class这样的名称,以及空URL。
Class clazz = Class.forName(nameOfClassYouWant);
URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".", "/") + ".class");
InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish
String className = MyClass.class.getName().replace(".", "/")+".class";
URL classUrl = MyClass.class.getClassLoader().getResource(className);
String fullPath = classUrl==null ? null : classUrl.getPath();