相同包名+类名在不同目录下或者jar内同时存在时的加载顺序
1.结论:根据classpath 顺序加载
2.源码:
java.net.URLClassLoader#findClass
protected Class<?> findClass(final String name) throws ClassNotFoundException
{
final Class<?> result;
try {
result = AccessController.doPrivileged(
new PrivilegedExceptionAction<Class<?>>() {
public Class<?> run() throws ClassNotFoundException {
String path = name.replace('.', '/').concat(".class");
// 调用sun.misc.URLClassPath#getResource(java.lang.String, boolean) 查找class文件
Resource res = ucp.getResource(path, false);
if (res != null) {
try {
return defineClass(name, res);
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
} catch (ClassFormatError e2) {
if (res.getDataError() != null) {
e2.addSuppressed(res.getDataError());
}
throw e2;
}
} else {
return null;
}
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
}
if (result == null) {
throw new ClassNotFoundException(name);
}
return result;
}
sun.misc.URLClassPath#getResource(java.lang.String, boolean)
public Resource getResource(String name, boolean check) {
if (DEBUG) {
System.err.println("URLClassPath.getResource(\"" + name + "\")");
}
//根据Loader的顺序查找 ,第一个找到就返回, loader顺序来自classpath顺序
Loader loader;
int[] cache = getLookupCache(name);
for (int i = 0; (loader = getNextLoader(cache, i)) != null; i++) {
Resource res = loader.getResource(name, check);
if (res != null) {
return res;
}
}
return null;
}
根据classpath创建AppClassLoader
sun.misc.Launcher.AppClassLoader#getAppClassLoader
public static ClassLoader getAppClassLoader(final ClassLoader extcl) throws IOException {
final String s = System.getProperty("java.class.path");
// 获取classpath
final File[] path = (s == null) ? new File[0] : getClassPath(s);
// Note: on bugid 4256530
// Prior implementations of this doPrivileged() block supplied
// a rather restrictive ACC via a call to the private method
// AppClassLoader.getContext(). This proved overly restrictive
// when loading classes. Specifically it prevent
// accessClassInPackage.sun.* grants from being honored.
//
return AccessController.doPrivileged(
new PrivilegedAction<AppClassLoader>() {
public AppClassLoader run() {
URL[] urls (s == null) ? new URL[0] : pathToURLs(path);
// 创建AppClassLoader
return new AppClassLoader(urls, extcl);
}
}
);
}
3.示例验证:
启动命令添加 -verbose:class 打印类加载信息