Java 类加载器-简单

Now我们来简单了解一下Java的类加载器。

类加载器 简述

大家都知道,完整的Java程序由n个.class文件组成。Java程序运行时,类加载器并不会加载全部class文件,而是“按需加载”。一开始,类加载器会先加载入口函数“main”所在的class,并运行“main”方法。在“main”方法中,我们调用了哪个类(如 new Student),就将哪个类的class(Student.class)文件加载到内存中。所以说类加载器是用于“动态”加载class文件的。

加载类机制 双亲机制

在加载Java类时,会使用很多类型的加载器,如Bootstrap ClassLoader,Extension ClassLoader,App ClassLoader等。除了Bootstrap ClassLoader(这是最顶层的类加载器),每个类加载器都有一个父加载器(非继承),当某个ClassLoader(ClassLoader A)实例想要加载一个类时,并不会直接加载,而是先委托父加载器App ClassLoader去加载,如果App ClassLoader还有父加载器,继续向上委托,一直到Bootstrap ClassLoader。所以Bootstrap ClassLoader是最先尝试加载某个类,如果Bootstrap ClassLoader没有找到想要加载的class,交给下一个Extension ClassLoader加载去加载。如果Extension ClassLoader还是没有找到,交给App ClassLoader去加载,如果还是没有找到,交给具体ClassLoader(ClassLoader A)去加载,如果还是没有找到,则抛出ClassNotFoundException 异常。

双亲机制的好处

使用双亲机制来加载类,可以避免重载加载,如果父加载器已经加载目标类了,那么子类没必要再加载一次相同的类。为什么要避免重复加载类呢?如果可以重复加载,我们可以重新定义java核心api中定义的类型,如String类,然后我们来动态代替这些类,这样会破坏系统,带来非常大的安全隐患。使用双亲机制就可以避免加载我们自定义的String类了。

Android类加载器

对于 Android 而言,最终的 apk 文件包含的是 dex 类型的文件,dex文件是将 class 文件重新打包,打包的规则又不是简单地压缩,而是完全对class 文件内部的各种函数表,变量表进行优化,产生一个新的文件,即dex文件。因此加载这种特殊的 Class 文件就需要特殊的类加载器DexClassLoader。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在一个应用程序中同时加载两个版本的OJDBC驱动是比较困难的,因为Java类加载器默认使用委派模型,即当一个类需要被加载时,它首先会请求其父类加载器加载该类,如果父类加载器无法加载该类,则由当前类加载器尝试加载该类。 为了解决这个问题,我们可以使用自定义类加载器来加载不同版本的OJDBC驱动。自定义类加载器可以绕过默认的委派模型,从而使得我们可以在同一个应用程序中加载不同版本的类。 下面是一个简单的例子,演示如何使用自定义类加载器加载两个版本的OJDBC驱动: ```java import java.net.URL; import java.net.URLClassLoader; public class CustomClassLoader extends URLClassLoader { public CustomClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { if (name.startsWith("oracle.jdbc.")) { String version = System.getProperty("oracle.jdbc.version"); if (version != null && version.equals("11g")) { return loadClassFromVersion(name, "11g"); } else { return loadClassFromVersion(name, "12c"); } } return super.loadClass(name); } private Class<?> loadClassFromVersion(String name, String version) throws ClassNotFoundException { String className = name.replace(".", "/") + ".class"; URL url = getResource(className.replace(version, "common")); if (url == null) { throw new ClassNotFoundException(name); } byte[] bytes = null; try { bytes = IOUtils.toByteArray(url.openStream()); } catch (IOException e) { throw new ClassNotFoundException(name, e); } return defineClass(name, bytes, 0, bytes.length); } } ``` 在这个自定义类加载器中,我们重写了loadClass方法,并根据系统属性oracle.jdbc.version的值来判断应该加载哪个版本的OJDBC驱动。 如果oracle.jdbc.version的值为11g,则加载11g版本的驱动,否则加载12c版本的驱动。 在loadClass方法中,我们首先判断要加载的类是否以oracle.jdbc.开头,如果是,则调用loadClassFromVersion方法加载对应版本的类。 在loadClassFromVersion方法中,我们首先使用getResource方法获取该类对应的URL,然后读取该URL对应的字节码,并使用defineClass方法将该类加载到内存中。 最后,我们在应用程序中使用自定义类加载器来加载OJDBC驱动: ```java URL[] urls = new URL[] { new URL("file:///path/to/ojdbc11.jar"), new URL("file:///path/to/ojdbc12.jar") }; ClassLoader parent = ClassLoader.getSystemClassLoader(); CustomClassLoader loader = new CustomClassLoader(urls, parent); System.setProperty("oracle.jdbc.version", "11g"); // 设置oracle.jdbc.version属性为11g Class<?> driverClass = loader.loadClass("oracle.jdbc.driver.OracleDriver"); Driver driver = (Driver) driverClass.newInstance(); ``` 在这个例子中,我们首先创建一个CustomClassLoader对象,并将ojdbc11.jar和ojdbc12.jar的URL作为参数传入。 然后,我们设置oracle.jdbc.version属性为11g,并使用CustomClassLoader加载对应版本的OracleDriver类,并创建该类的实例。 这样,我们就可以在同一个应用程序中同时使用不同版本的OJDBC驱动了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值