Java最新今天被面试官吼了一顿:JVM-类加载都不会 你好意思来面试?,Java研发岗必问30+道高级面试题

面试题总结

其它面试题(springboot、mybatis、并发、java中高级面试总结等)

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

需要这份系统化的资料的朋友,可以点击这里获取

public byte[] loadClassData(String name) {

System.out.println(“abc”);

InputStream is = null;

byte[] data = null;

ByteArrayOutputStream byteArrayOutputStream = null;

try {

this.classLoaderName = name.replace(“.”, “/”);

String fileExtension = “.class”;

is = new FileInputStream(path.concat(classLoaderName).concat(fileExtension));

byteArrayOutputStream = new ByteArrayOutputStream();

int ch = 0;

while (-1 != (ch = is.read())) {

byteArrayOutputStream.write(ch);

}

data = byteArrayOutputStream.toByteArray();

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

assert is != null;

is.close();

assert byteArrayOutputStream != null;

byteArrayOutputStream.close();

} catch (Exception e) {

e.printStackTrace();

}

}

return data;

}

@Override

protected Class<?> findClass(String name) {

byte[] data = loadClassData(name);

return this.defineClass(name, data, 0, data.length);

}

}

复制代码

测试一下,我删除了target目录下的MyTest.class,然后将MyTest.class移动到/Users/zhangxiaobin/Desktop这个目录下,findClass时系统类加载器没有加载到MyTest.class,自定义类加载器就能够加载到这个类了

public static void main(String[] args) throws Exception {

// 定义第一个类加载器

MyClassLoader myClassLoader = new MyClassLoader(“myClassLoader”, “/Users/zhangxiaobin/Desktop/”);

Class<?> clazz = myClassLoader.loadClass(“com.example.jvm.MyTest”);

Object object = clazz.newInstance();

System.out.println(object);

System.out.println(clazz.getClassLoader());

System.out.println(clazz.getClassLoader().getParent());

System.out.println(clazz.hashCode());

// 定义第二个类加载器

MyClassLoader myClassLoader2 = new MyClassLoader(“myClassLoader”, “/Users/zhangxiaobin/Desktop/”);

Class<?> clazz2 = myClassLoader2.loadClass(“com.example.jvm.MyTest”);

Object object2 = clazz2.newInstance();

System.out.println(object2);

System.out.println(clazz.getClassLoader());

System.out.println(clazz.getClassLoader().getParent());

System.out.println(clazz2.hashCode());

}

复制代码

测试一下,发现自定义了两个类加载器,同一个类被加载了两次,这是因为类加载器有一个命名空间的问题,每个类加载器都有自己的命名空间,在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类,在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类

将target目录下的MyTest.class弄回来,会发现该类是使用了系统类加载器来加载的

类加载器命名空间的一些问题
  1. 同一个命名空间内的类是相互可见的

  2. 子加载器的命名空间包含所有父加载器的命名空间,因此由子加载器加载的类能看到父加载器加载的类,父加载器加载的类不能看到子加载器加载的类

  3. 如果两个加载器之间没有直接或间接的父子关系,那么他们各自加载的类相互不可见

SPI打破双亲委派机制

在类加载器命名空间的限制下,双亲委派机制在某些场景下无法满足我们的需求,比如SPI机制

Java核心类库定义了接口,并未给出实现,这些接口的实现来自不同的jar包(厂商),比如JDBC,Java核心类库定义了Connection等接口,不同的厂商有不同的实现,MySQL、Oracle等等,这些实现是通过jar包的方式加载的,jar包位于ClassPath下。Java核心类库是由启动类加载器加载的,ClassPath下的jar包是由系统类加载器加载的,按照命名空间的规则,他们是不可见的

办法总比问题多,jdk在双亲委派机制的基础上,新增了线程上下文类加载器,通过给当前线程设置线程上下文类加载器的方式来实现对于接口实现类的加载

这个线程上下文类加载器一般是系统类加载器

// 具体设置的代码在Launcher这个类中

public Launcher() {

// Create the extension class loader

ClassLoader extcl;

try {

// 获取扩展类加载器

extcl = ExtClassLoader.getExtClassLoader();

} catch (IOException e) {

throw new InternalError(

“Could not create extension class loader”, e);

}

// Now create the class loader to use to launch the application

try {

// 获取系统类加载器

loader = AppClassLoader.getAppClassLoader(extcl);

} catch (IOException e) {

throw new InternalError(

“Could not create application class loader”, e);

}

// 将线程上下文类加载器设置为系统类加载器,此加载器是可以替换的

Thread.currentThread().setContextClassLoader(loader);

}

复制代码

SPI机制是通过ServiceLoader这个类进行实现类的加载

public static ServiceLoader load(Class service) {

// 可以看到,获取了线程上下文类加载器来加载类

ClassLoader cl = Thread.currentThread().getContextClassLoader();

return ServiceLoader.load(service, cl);

}

复制代码

示意图如下

链接

链接分为三步,分别是验证、准备、解析

验证:确保Class文件中包含的信息符合Java虚拟机的规范

最后总结

ActiveMQ+Kafka+RabbitMQ学习笔记PDF

image.png

  • RabbitMQ实战指南

image.png

  • 手写RocketMQ笔记

image.png

  • 手写“Kafka笔记”

image

关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦

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

需要这份系统化的资料的朋友,可以点击这里获取

mcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦

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

需要这份系统化的资料的朋友,可以点击这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值