说我有以下内容:
public class Foo {
static {
System.out.println("Foo static initialization is working")
}
public void sayHello {
System.out.println("Hello Foo")
}
}
public class Bar {
static {
System.out.println("Bar static initialization is working")
}
public void sayHello {
System.out.println("Hello Bar")
}
}
public class HelloMain {
public static void main() {
Foo foo = new Foo();
foo.sayHello();
Bar bar = new Bar();
bar.sayHello();
}
}
这是我的自定义classLoader:
public class MyClassLoader extends ClassLoader {
public MyClassLoader() {
super(MyClassLoader.class.getClassLoader());
}
public MyClassLoader(ClassLoader parent){
super(parent);
}
public Class loadClass(String name) throws ClassNotFoundException {
System.out.println(name + " ************"); // why Foo and Bar are not coming through here?
return super.loadClass(name);
}
}
假设我将所有这些打包为jar,我的jar文件的名称为" hello.jar" 并运行以下命令:
java -Djava.system.class.loader=MyClassLoader -jar hello.jar
它打印了上面代码中的所有标准java类和HelloMain类,但是没有打印Foo和Bar类。我想知道为什么?另外,我如何更改某些内容,以便MyClassLoader中的print语句打印Foo和Bar类?
答案 0 :(得分:1)
请参阅此SO文章:Difference between thread's context class loader and normal classloader
重要的一点是,虽然要求您的类加载器加载HelloMain
,但它不是那样做的,因为您只是委托给了超级类,该类被委托给父类加载器
由于父类加载器已加载HelloMain
,因此 HelloMain
引用的所有类也将从父类加载器加载,并且不会询问您的类加载器。
只会要求您的类加载器为从类加载器加载的类加载引用的类。
要解释原因,请考虑具有不同独立类加载器(A和B)的两个线程。类加载器A不知道如何从B加载类,反之亦然。
如果线程A创建了一个对象并为线程B提供了对象,那么JVM需要加载由线程B执行的操作引用的类,如果询问线程B的类加载器,它将无法工作。因此,使用对象的类加载器,而不是线程的类加载器。
为了显示线程类加载器(称为上下文类加载器)和加载类的类加载器之间的区别,我更新了代码:
public class MyClassLoader extends ClassLoader {
public MyClassLoader() {
super(MyClassLoader.class.getClassLoader());
System.out.println("MyClassLoader()");
}
public MyClassLoader(ClassLoader parent) {
super(parent);
System.out.println("MyClassLoader(" + parent + ")");
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
System.out.println("MyClassLoader.loadClass(\"" + name + "\")");
return super.loadClass(name);
}
}
public class HelloMain {
public static void main(String[] args) {
System.out.println("Hello from HelloMain");
System.out.println(" Loaded by " + HelloMain.class.getClassLoader());
System.out.println(" Context class loader: " + Thread.currentThread().getContextClassLoader());
Foo foo = new Foo();
foo.sayHello();
Bar bar = new Bar();
bar.sayHello();
}
}
public class Foo {
static {
System.out.println("Foo loaded");
}
public void sayHello() {
System.out.println("Hello from Foo");
System.out.println(" Loaded by: " + getClass().getClassLoader());
System.out.println(" Context class loader: " + Thread.currentThread().getContextClassLoader());
}
}
public class Bar {
static {
System.out.println("Bar loaded");
}
public void sayHello() {
System.out.println("Hello from Bar");
System.out.println(" Loaded by: " + getClass().getClassLoader());
System.out.println(" Context class loader: " + Thread.currentThread().getContextClassLoader());
}
}
输出(使用jdk1.8.0_91)
MyClassLoader(sun.misc.Launcher$AppClassLoader@18b4aac2)
MyClassLoader.loadClass("HelloMain")
Hello from HelloMain
Loaded by sun.misc.Launcher$AppClassLoader@18b4aac2
Context class loader: MyClassLoader@6d06d69c
Foo loaded
Hello from Foo
Loaded by: sun.misc.Launcher$AppClassLoader@18b4aac2
Context class loader: MyClassLoader@6d06d69c
Bar loaded
Hello from Bar
Loaded by: sun.misc.Launcher$AppClassLoader@18b4aac2
Context class loader: MyClassLoader@6d06d69c
答案 1 :(得分:0)
public class MyClassLoader extends URLClassLoader {
public MyClassLoader() throws Exception{
super(new URL[]{new URL("file:///home/ubuntu/java/hello.jar")});
}
@Override
public Class loadClass(String name) throws ClassNotFoundException {
if (name.equals("hello.example.org.Foo") || name.equals("hello.example.org.Bar"))
{
System.out.println("Foo or Bar is loaded");
}
return super.loadClass(name);
}
}