jvm 里 class 的唯一标识是 classloader+包+类
现在我自定义了一个 classloader
public class MyClassLoader extends ClassLoader
从外部加载指定类进入 jvm
MyClassLoader mcl = new MyClassLoader();
Class<?> clazz = Class.forName("com.yuhan.demo.controller.People", true, mcl);
obj = clazz.newInstance();
System.out.println(obj.getClass().getClassLoader());//打印出我们的自定义类加载器
这种加载方法应该是使用了双亲委托机制如果 AppClassLoader 已经加载过 People 了则不会重新加载
控制台输出
sun.misc.Launcher$AppClassLoader@73d16e93
如果我们将 People.class 从 classpath 中删除放到其他地方,避免 AppClassLoader 直接加载
则输出
com.yuhan.demo.controller.MyClassLoader@15db9742
但是如果我们直接这样调用
mcl = new MyClassLoader();
aClass = mcl.findClass("com.yuhan.demo.controller.People");
obj =aClass.newInstance();
System.out.println(obj.getClass().getClassLoader());//打印出我们的自定义类加载器
则不管 AppClassLoader 是否加载过都会由 MyClassLoader 来加载(相当于绕过了双亲?)
现在我有个疑问就是我用 findClass 方法加载了一个 jvm 中已经存在的 class(包名类名都相同),相当于 jvm 中就有两个相同的 class 了(jvm 中是允许这样存在的因为 classloader 不同) 但是 java 中使用类的时候只指定了包名和类名并没有指定 classloader 那么 java 是如何保证我 new People 的时候是是用的 AppClassLoader 的 People 而不是 MyClassLoader 的 People 呢
我的猜测是我们直接使用类的时候 java 加上了默认的 classloader 从而过滤调了我们自己加载的类,而我们自己加载的类则只能通过反射来调用
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.