我开发了一个普通的Java项目,我试图理解ClassNotFoundException
和NoClassDefFoundException
之间的区别。我发现了一个奇怪的行为,当我调用Class.forName()
时,我需要包含整个包结构。
请参阅以下代码:
package org.com;
public class MainApp {
public static void main(String[] args) {
try {
Class cls = Class.forName("org.com.MainApp");
System.out.println("Class = " + cls.getName());
} catch(ClassNotFoundException ex) {
System.out.println(ex.toString());
}
}
}
如果我使用Class.forName("MainApp")
代替Class.forName("org.com.MainApp")
,则会抛出异常。
有人可以解释一下这个的实际原因吗?
答案 0 :(得分:7)
基本上,因为the contract says so:
className - 所需类的完全限定名称。
你可以在不同的包中有两个名为MainApp
的类。如果省略完全限定名称(即包括包),类加载器将如何知道要加载哪个类?
换句话说,这是一个设计决定,在我看来,是一个好的。
Class.forName("MainApp")
实际上会尝试加载位于默认包中的名为MainApp
的类,即该类中未指定包名。
答案 1 :(得分:5)
因为您的类存在于该包中,而forName方法需要完全限定名称
假设java有一个AI来通过仅指定名称来识别你的类,当你指定“Date”时会发生什么?
Class cls = Class.forName("Date");
是否需要为您提供java.util. Date
课程或java.sql.Date
课程或任何第三方资料库日期课程?
这就是为什么你需要指定包名来唯一标识该类
答案 2 :(得分:2)
Class.forName没有关于你的类的任何概念或它的调用位置。
这是一个通用工具。
例如:
你是这个名叫亚历山大的城市中唯一的人。 您通过亚马逊订购包裹,然后将其交付给亚历山大。
从你的角度来看,你是这个城市唯一的亚历山大人,很容易吗?
现在从亚马逊的角度来看......他们不知道在哪里发送它。
同样的逻辑适用于class.forName。
答案 3 :(得分:1)
当你编译代码时,编译器知道你正在编译哪个包以及你导入了哪些类,所以当你给它一个类名时,它可以检查这些东西以找到你想要的完全限定的类名。
但是,Class.forName
是类Class
上的方法。它只知道你传递了什么,类名。它不知道调用者的包,也不知道您使用的是什么。只有完全限定的类名才能工作。
答案 4 :(得分:1)
简单回答:
同一个类可能是多个包的一部分,而JVM不确定要加载哪个类。
MainApp
和package1
可能有package2
个课程。
为避免含糊不清,Class.forName
e.g。
Class.forName("package1.MainApp")
Class.forName("package2.MainApp")
来自documentation页面的说明:
public static Class<?> forName(String className)
throws ClassNotFoundException
返回与具有给定字符串名称的类或接口关联的Class对象。调用此方法相当于: Class.forName(className,true,currentLoader)
参数:
className - 所需类的完全限定名称。
返回:具有指定名称的类的Class对象。