最近遇到一个问题:
1. 我的类A
2. ThreadB线程的类加载器ClassLoaderB没有加载权限
3. 使用另一个线程ThreadA的类加载器ClassLoaderA加载类A,创建对象a
4. 将a给线程ThreadB,然后调用其toString()方法
5. 发现调用的是类A的toString(),而不是Object的toString()
具体代码如下
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.CountDownLatch;
public class TestClassLoader {
public static Object obj;
public static void main(String[] args) {
AClassLoader cl = new AClassLoader();
cl.addURL("a.jar");
final CountDownLatch cdl = new CountDownLatch(1);
Thread t = new Thread(new Runnable(){
@Override
public void run() {
try {
Class<?> cls = Thread.currentThread().getContextClassLoader().loadClass("com.abcd.ABCD");
try {
obj = cls.newInstance();
System.out.println("in : " + obj.toString());
cdl.countDown();
} catch (Exception e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
});
t.setContextClassLoader(cl);
t.start();
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(obj);
Class<?> cls = null;
try {
cls = Thread.currentThread().getContextClassLoader().loadClass("com.abcd.ABCD");
} catch (ClassNotFoundException e1) {
//出现ClassNotFoundException
e1.printStackTrace();
}
try {
obj = cls.newInstance();
System.out.println("in : " + obj.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
class AClassLoader extends URLClassLoader{
public AClassLoader(){
super(new URL[0]);
}
public void addURL(String filePath){
File file = new File(filePath);
URI uri = file.toURI();
try {
addURL(uri.toURL());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
类ABCD的代码
import java.lang.System;
import java.lang.String;
public class ABCD{
public ABCD(){
}
@Override
public String toString(){
return "abcd";
}
}
得出的结果是
in : abcd
abcd
java.lang.ClassNotFoundException: com.abcd.ABCD
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at TestClassLoader.main(TestClassLoader.java:46)
java.lang.NullPointerException
at TestClassLoader.main(TestClassLoader.java:52)
得出结论:
类加载器只有在类加载时会起到指示安全域的作用,但对象一旦被创建后,可以调用其Object的@Override方法