深入浅出Java类加载机制,java软件工程师面试题目

c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
//如果找不到类,则抛出ClassNotFoundException
}
//第二次检查Class是否被加载–双短检查加锁机制保障Class的唯一性
if (c == null) {
long t1 = System.nanoTime();
//如果仍然找不到,请按顺序调用findClass顺序查找当前Class
c = findClass(name);
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
//是否需要在Class加载后调用class的初始化代码块
if (resolve) {
resolveClass©;
}
return c;
}
}

从上述的源码以及我添加的注释中,我们大概明白了,在loadClass方法执行过程中,还会传递一个resolve标示符,此标示符和forName的initialize参数是一样的,用来判断是否在Class加载后进行初始化代码块的操作,但是我们从上面的方法明显看到,默认传递的值为false,即仅仅加载Class类,并不去调用类的初始化代码块部分,两者的区别至此已经真相大白

自定义ClassLoader

前面我们也多次提到过自定义ClassLoader,此技术也是tomcat、OSGI等实现应用隔离、动态模块加载的基础,那么如何自定义呢?一般来说,我们需要继承类ClassLoader,重写其方法findClass即可,现在我们来看一个开发中常遇到的问题:我们在开发过程中经常遇到本地运行程序的情况,往往有些时候会遇到服务端的jar与我们自定义的代码中有部分类名一致的时候,因为系统加载的时候默认优先显示服务端的jar中的calss,而不是本地的class,那么究其原因,就是jvm默认使用AppClassLoader加载classpath中的类 ,那么我们能否重写AppClassLoader来实现优先显示本地实现的类,再去加载服务端的jar中呢?说做就做,我们参考系统默认实现的URLClassLoader 类的代码来写一个简单的功能实现,代码如下:

public class MyClassLoader extends URLClassLoader {
public URLClassPath ucp;
private Map<String, Class<?>> cache = new HashMap();
private static final Method defineClassNoVerifyMethod;

static String[] paths = System.getProperty(“java.class.path”).split(“;”);

static URL[] urls = new URL[paths.length];

//初始化每一个类的URL
static{
for(int i=0; i<urls.length; i++){
try {
urls[i] = new URL(“file:”+paths[paths.length-1-i]);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
System.out.println(Arrays.toString(urls));

SharedSecrets.setJavaNetAccess(new JavaNetAccess() {
public URLClassPath getURLClassPath(URLClassLoader u) {
return ((MyClassLoader)u).ucp;
}
@Override
public String getOriginalHostName(InetAddress inetAddress) {
return null;
}
} );

Method m;
try {
m = SecureClassLoader.class.getDeclaredMethod(“defineClassNoVerify”,
new Class[] { String.class, ByteBuffer.class, CodeSource.class });
m.setAccessible(true);
} catch (NoSuchMethodException nsme) {
m = null;
}
defineClassNoVerifyMethod = m;
}

public MyClassLoader(URL[] urls) {
super(MyClassLoader.urls);
this.ucp = new URLClassPath(MyClassLoader.urls);
}

public MyClassLoader(ClassLoader parent) {
super(MyClassLoader.urls, parent);
this.ucp = new URLClassPath(MyClassLoader.urls);
}

//重写loadClass,实现自定义的类加载
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException{
Class c = null;
if (name.contains(“hadoop”)) {
c = (Class)this.cache.get(name);
if (c == null) {
c = findClass(name);
this.cache.put(name, c);
}
} else {
c = loadClass(name, false);
}
return c;
}

protected Class<?> findClass(String name) throws ClassNotFoundException {
//替换路径查找对应的类资源
String path = name.replace(‘.’, ‘/’).concat(“.class”);
Resource res = this.ucp.getResource(path);
if (res != null) {
try {
return defineClass(name, res, true);
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
}
throw new ClassNotFoundException(name);
}

private Class<?> defineClass(String name, Resource res, boolean verify) throws IOException {
int i = name.lastIndexOf(‘.’);
URL url = res.getCodeSourceURL();
if (i != -1) {
//根据class最后一个.的下标截取包名
String pkgname = name.substring(0, i);
Package pkg = getPackage(pkgname);
Manifest man = res.getManifest();
if (pkg != null){
//校验当前包名是否为私密包名
if (pkg.isSealed()){
if (!pkg.isSealed(url)){
throw new SecurityException(
“sealing violation: package " + pkgname +
" is sealed”);
}
}
else if ((man != null) && (isSealed(pkgname, man))) {
throw new SecurityException(
"sealing violation: can’t seal package " +
pkgname + “: already loaded”);
}
}
//Manifest不为null
else if (man != null)
definePackage(pkgname, man, url);
else {
definePackage(pkgname, null, null, null, null, null, null,
null);
}
}

ByteBuffer bb = res.getByteBuffer();
byte[] bytes = bb == null ? res.getBytes() : null;
CodeSigner[] signers = res.getCodeSigners();
CodeSource cs = new CodeSource(url, signers);

if (!verify){
Object[] args = { name, bb == null ? ByteBuffer.wrap(bytes) : bb,cs };
try {
return (Class)defineClassNoVerifyMethod.invoke(this, args);
}
catch (IllegalAccessException localIllegalAccessException) {}
catch (InvocationTargetException ite) {
Throwable te = ite.getTargetException();
if ((te instanceof LinkageError))
throw ((LinkageError)te);
if ((te instanceof RuntimeException)) {
throw ((RuntimeException)te);
}
throw new RuntimeException("Error defining class " + name,
te);
}
}
return defineClass(name, bytes, 0, bytes.length, cs);
}

//校验是否为私密(密闭)包==>查找类路径是否存在
private boolean isSealed(String name, Manifest man) {

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

最后

看完美团、字节、腾讯这三家的面试问题,是不是感觉问的特别多,可能咱们又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。

开篇有提及我可是足足背下了1000道题目,多少还是有点用的呢,我看了下,上面这些问题大部分都能从我背的题里找到的,所以今天给大家分享一下互联网工程师必备的面试1000题

注意不论是我说的互联网面试1000题,还是后面提及的算法与数据结构、设计模式以及更多的Java学习笔记等,皆可分享给各位朋友

最新“美团+字节+腾讯”一二三面问题,挑战一下你能走到哪一面?

互联网工程师必备的面试1000题

而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题

最新“美团+字节+腾讯”一二三面问题,挑战一下你能走到哪一面?

-OQIXqsGK-1711178282337)]

互联网工程师必备的面试1000题

而且从上面三家来看,算法与数据结构是必备不可少的呀,因此我建议大家可以去刷刷这本左程云大佬著作的《程序员代码面试指南 IT名企算法与数据结构题目最优解》,里面近200道真实出现过的经典代码面试题

[外链图片转存中…(img-0bV7Fs1W-1711178282337)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值