类加载器不能完全按照您的预期执行。
Quoting 另一个答案 https://stackoverflow.com/a/10192692/6730571相关问答:
Java 将始终使用加载正在执行的代码的类加载器。
以你的例子为例:
public static void main(String[] args) {
// whatever you do here...
Car car = new Car(); // ← this code is already bound to system class loader
}
你能得到的最接近的结果是使用子优先(父最后)类加载器例如this one https://stackoverflow.com/a/5446671/6730571,用你的 jar 实例化它,然后使用反射创建一个实例Car
从那个罐子里。
Car
类内a.jar
:
package com.acme;
public class Car {
public String honk() {
return "Honk honk!";
}
}
您的主要应用:
public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(
Arrays.asList(new File("/home/lib/custom/a.jar").toURI().toURL()));
Class<?> carClass = classLoader.loadClass("com.acme.Car");
Object someCar = carClass.newInstance();
Object result = carClass.getMethod("honk").invoke(someCar);
System.out.println(result); // Honk honk!
}
需要注意的是:如果您也有com.acme.Car
类路径中的 .class ,这不是同一个类,因为类是通过其全名和类加载器来标识的。
为了说明这一点,假设我使用了本地Car
类如下carClass
由我的自定义类加载器按上述方式加载:
Car someCar = (Car) carClass.newInstance();
// java.lang.ClassCastException: com.acme.Car cannot be cast to com.acme.Car
可能会令人困惑,但这是因为名称本身并不能识别类。该转换无效,因为这两个类不同。它们可能具有不同的成员,或者它们可能具有相同的成员但不同的实现,或者它们可能是逐字节相同的:它们不是同一个类。
现在,这并不是一件很有用的事情。
这样的事情就变成了当 jar 中的自定义类实现通用 API(主程序知道如何使用)时很有用.
例如,假设接口Vehicle
(其中有方法String honk()
) 位于公共类路径中,并且您的Car
is in a.jar
并实施Vehicle
.
ParentLastURLClassLoader classLoader = new ParentLastURLClassLoader(
Arrays.asList(new File("/home/lib/custom/a.jar").toURI().toURL()));
Class<?> carClass = classLoader.loadClass("com.acme.Car");
Vehicle someCar = (Vehicle) carClass.newInstance(); // Now more useful
String result = someCar.honk(); // can use methods as normal
System.out.println(result); // Honk honk!
这与 servlet 容器的作用类似:
- 您的应用程序实现了 servlet API(例如,实现了
javax.servlet.Servlet
)
- 它被打包成一个 war 文件,servlet 容器可以使用自定义类加载器加载该文件
- 部署描述符(
web.xml
文件)告诉 servlet 容器它需要实例化的 servlet(类)的名称(如我们上面所做的那样)
- 这些课程是
Servlet
s,servlet 容器可以这样使用它们