Java osgi框架中class.forName()和classLoader.loadClass()之间的区别是什么

Java osgi框架中class.forName()和classLoader.loadClass()之间的区别是什么,java,osgi,classnotfoundexception,Java,Osgi,Classnotfoundexception,我正在使用ApacheFelixOSGi。当我使用classLoader.loadClass(..)加载类时,它给出了ClassNotFoundException 但是当我使用Class.forName()加载一个类时,它工作得很好 当我们使用classLoader.loadClass()时有什么区别?。为什么我们只需要使用Class.forName()或者如何正确使用classLoader.loadClass()?classLoader.loadClass或者Class.forName似乎是相

我正在使用ApacheFelixOSGi。当我使用
classLoader.loadClass(..)
加载类时,它给出了
ClassNotFoundException
但是当我使用
Class.forName()
加载一个类时,它工作得很好


当我们使用
classLoader.loadClass()
时有什么区别?。为什么我们只需要使用
Class.forName()
或者如何正确使用
classLoader.loadClass()

classLoader.loadClass
或者
Class.forName
似乎是相同基本操作的同义词:请求动态类加载。但是调用
Class.forName
会进行额外的“检查”,这不是很有用(当然在OSGi中)

在执行动态类加载时,返回的类型没有代码所暗示的类型。代码必须使用反射来访问静态成员或创建实例。创建的实例既可以反映在类型上,也可以转换为代码必须已经隐式知道的类型。此强制转换将导致运行时类型检查,这将确保类型安全

这与VM为解析类常量池条目而执行的隐式类加载非常不同。由于这些隐式类加载的目标是避免运行时类型检查,因此使用加载程序约束来确保类型安全

对某些动态类加载请求强制进行加载程序约束检查似乎没有必要或不合理。也就是说,代码调用
Class.forName
(或
ClassLoader.loadClass
)和解析类常量池条目的VM具有不同的类型安全需求。前者不需要加载程序约束检查,因为这将在运行时由类型转换(如果需要)完成。后者确实需要加载程序约束检查,以避免需要运行时类型检查

因此,更改
Class.forName
行为以避免加载程序约束检查似乎是合理的。只有内部
VM
类加载请求需要检查加载程序约束

为了更好地理解

方法Class.forName(String)使用调用方的类加载器。例如,如果你正在做

class MyClass {
    void someMethod() {
        Class.forName("my.pkg.SomeClass");
    }
}
然后,加载类MyClass的类加载器也加载类“my.pkg.SomeClass”。在独立应用程序中,这通常是所谓的系统类加载器

如果您看到使用Class.forName和ClassLoader.loadClass之间存在差异,那么您使用的是另一个类加载器


OSGI中的类加载更为困难,因为OSGI很好地将所有OSGI捆绑包的类加载程序分开,以避免在加载所有资源和类时发生冲突。

在任何模块化环境(如OSGI)中,仅按名称加载类是不够的,因为许多模块可能有一个同名的类。因此,必须使用类名和应加载该类的模块来唯一标识该类

如果以单个参数形式调用
Class.forName()
,则无法提供模块信息,因此Java转而使用调用方的类加载器。这并不比随机猜测好多少。在你的情况下,它只是碰巧工作(它找到了类),但只有通过纯粹的运气

如果调用
ClassLoader.loadClass()
,请注意这不是一个静态方法,那么您实际上提供了一个类加载器。这好多了!不幸的是,您提供了错误的加载程序,即,不是真正了解该类的加载程序。你没有说明你从哪里得到这个加载器,所以我只能推测它为什么错了

更好的方法是使用OSGi的
Bundle.loadClass()
方法,它允许您显式地从Bundle加载类。同样,您需要知道类应该来自哪个包,但这是在模块化环境中工作的必然结果


最后,最好还是完全忘记动态类加载,学习如何使用服务。除了处理需要动态类加载的第三方库或传统库时,您永远不必在OSGi中使用动态类加载。

作为附加提示:由于出现了异常,您可能通过调用
Thread.currentThread().getContextClassLoader()
获得了您称为
类加载程序的类加载程序。在OSGi环境中,这可能是最糟糕的类装入器,因为它的设置完全没有定义。加载可能会一次失败,另一次成功,导致难以发现的问题。

感谢arievanwi的回答,您的回答完全正确。我只在我的类中使用Thread.currentThread().getContextClassLoader(),因此我可以知道如何避免此异常,您可以告诉我避免此错误的替代方法吗?如何在osgi中获得类加载器。正如Neil已经指出的,这取决于。如果您确定要加载的类以某种方式导入到进行加载的捆绑包中(应该是这种情况),则可以安全地使用
getClass().getClassLoader()