深入java虚拟机学习 -- 类的加载机制(四)
类加载的命名空间
每个类加载器都有自己的命名空间,命名空间由所有以此加载器为初始类加载器的类组成,不同命名空间的两个类是不可见的,但只要得到类所对应的Class对象的refrence(反射),还是可以访问另一个命名空间的类信息的。
同一个命名空间内的类是相互可见的,子加载器的命名空间包含所有父加载器的命名空间,也就是说由子加载器加载的类能看到父加载器加载的类。例如:系统类加载器加载的类能看到根类加载器加载的类(用户自定的类可以访问java.lang.*包下的信息),由父加载器加载的类不能看到子加载器加载的类。
如果两个加载器之间没有直接或者间接的父子关系,那么它们个字加载的类相互不可见。
创建用户自定义的类加载器
要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定的类的名字,返回对应的Class对象的引用。
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
我们可以按到ClassLoader里面的findClass方法的默认实现会抛出ClassNotFoundException异常,我们只需要在自定义的加载器里面重写,即可。
public class MyClassLoader extends ClassLoader
{ private String name;//类加载器的名字
private String path="";//加载类的默认路径
private String fileType=".class"; //class文件的扩展名 public MyClassLoader(String name){
super();//让系统类加载器成为该类加载器的父加载器
this.name=name;
}
public MyClassLoader(ClassLoader parent,String name){
super(parent);//显示指定该类加载器的父加载器
this.name=name;
} @Override public String toString()
{
return this.name;
} public String getPath()
{
return path;
} public void setPath(String path)
{
this.path = path;
} /**
* 抽象类ClassLoader的findClass函数默认是抛出异常的。而前面我们知道,
* loadClass在父加载器无法加载类的时候,就会调用我们自定义的类加载器中的findeClass函数,
* 因此我们必须要在loadClass这个函数里面实现将一个指定类名称转换为Class对象.
* @param name
* @return
*/
@Override protected Class<?> findClass(String name)
{
byte [] data=this.loadClassData(name);
return this.defineClass(name,data,0,data.length);
} private byte[] loadClassData(String name)
{
InputStream is=null;
byte [] data=null;
ByteArrayOutputStream baos=null;
try
{
this.name=this.name.replace(".","\\");
is=new FileInputStream(new File(path+name+fileType));
baos=new ByteArrayOutputStream();
int ch=0;
while(-1!=(ch=is.read())){
baos.write(ch);
}
data= baos.toByteArray();
}
catch(Exception e){
e.printStackTrace();
}
finally
{
try
{
is.close();
baos.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
return data;
} public static void main(String[] args) throws Exception
{
MyClassLoader loader1 = new MyClassLoader("loader1");//没有指定loader的父加载器,则默认的父加载器为系统类加载器
loader1.setPath("G:\\myapp\\loader1\\"); MyClassLoader loader2 = new MyClassLoader(loader1,"loader2");//指定loader2的父加载器为loader1,这里的loader1和loader2都为MyClassLoader的实例
loader2.setPath("G:\\myapp\\loader2\\"); MyClassLoader loader3 = new MyClassLoader(null,"loader3");//bootstrap类加载器
loader3.setPath("G:\\myapp\\loader3\\"); //test(loader1);
test(loader2);
test(loader3);
} public static void test(ClassLoader loader) throws Exception
{
Class clazz=loader.loadClass("Sample");
Object object=clazz.newInstance();
}
深入java虚拟机学习 -- 类的加载机制(四)的更多相关文章
- 深入java虚拟机学习 -- 类的加载机制(续)
昨晚写 深入java虚拟机学习 -- 类的加载机制 都到1点半了,由于第二天还要工作,没有将上篇文章中的demo讲解写出来,今天抽时间补上昨晚的例子讲解. 这里我先把昨天的两份代码贴过来,重新看下: ...
- 深入java虚拟机学习 -- 类的加载机制
当看到"类的加载机制",肯定很多人都在想我平时也不接触啊,工作中无非就是写代码,不会了可以百度,至于类,jvm是怎么加载的我一点也不需要关心.在我刚开始工作的时候也觉得这些底层的内 ...
- 深入java虚拟机学习 -- 类的加载机制(三)
类的初始化时机 在上篇文章中讲到了类的六种主动使用方式,反射是其中的一种(Class.forName("com.jack.test")),这里需要注意一点:当调用ClasLoade ...
- Java基础_类的加载机制和反射
类的使用分为三个步骤: 类的加载->类的连接->类的初始化 一.类的加载 当程序运行的时候,系统会首先把我们要使用的Java类加载到内存中.这里加载的是编译后的.class文件 每个类加载 ...
- 深入java虚拟机学习 -- 类的卸载
类的生命周期 在开始本节之前让我们再来回顾下类的生命周期 没看过前6个过程的同学建议从头看下<深入java虚拟机学习 -- 类的加载机制>,这里就不再过多介绍了,着重说下类的卸载 类的卸载 ...
- jvm系列(一):java类的加载机制
java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装 ...
- JVM(1):Java 类的加载机制
原文出处: 纯洁的微笑 java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang. ...
- Java虚拟机学习笔记——JVM垃圾回收机制
Java虚拟机学习笔记——JVM垃圾回收机制 Java垃圾回收基于虚拟机的自动内存管理机制,我们不需要为每一个对象进行释放内存,不容易发生内存泄漏和内存溢出问题. 但是自动内存管理机制不是万能药,我们 ...
- jvm系列 (五) ---类的加载机制
类的加载机制 目录 jvm系列(一):jvm内存区域与溢出 jvm系列(二):垃圾收集器与内存分配策略 jvm系列(三):锁的优化 jvm系列 (四) ---强.软.弱.虚引用 我的博客目录 什么是类 ...
随机推荐
- C#仪器数据文件解析-PDF文件
不少仪器工作站输出的数据报告文件为PDF格式,PDF格式用于排版打印,但不易于数据解析,因此解析PDF数据需要首先读取到PDF文件中的文本内容,然后根据内容规则解析有意义的数据信息. C#解析PDF文 ...
- 分享一个集成在项目中的REST APIs文档框架swagger
1 为什么是使用swagger? 1-1 当后台开发人员开发好接口,是不是还要重新书写一份接口文档提给前端人员,当然对于程序员最不喜欢的就是书写文档(当然文档是必须的,有利于项目的维护) 1-2 当后 ...
- spring-boot-starter家族成员简介
应用程序starters 以下应用程序starters是Spring Boot在org.springframework.boot组下提供的: springboot使用指南https://docs.sp ...
- JS判断输入类型是否为正整数
需要用到正则表达式:"/^+?[1-9][0-9]*$/". 例子如下: <!DOCTYPE html> <html> <head> <m ...
- nyoj44 子串和 线性DP
线性DP经典题. dp[i]表示以i为结尾最大连续和,状态转移方程dp[i] = max (a[i] , dp[i - 1] + a[i]) AC代码: #include<cstdio> ...
- bash文件的详细解读
一.bash的分类 1. 按生效范围分类 全局生效 /etc/profile /etc/profile.d/*.sh /etc/bashrc 个人用户生效 ~/.bash_profile ~/.bas ...
- java数组:去重,增加,删除元素
import java.util.List; import java.util.ArrayList; import java.util.Set; import java.util.HashSet; p ...
- 3.1 PCI设备BAR空间的初始化
在PCI Agent设备进行数据传送之前,系统软件需要初始化PCI Agent设备的BAR0~5寄存器和PCI桥的Base.Limit寄存器.系统软件使用DFS算法对PCI总线进行遍历时,完成这些寄存 ...
- mysql学习笔记03 mysql数据类型
数值型:整数型 小数型字符串型时间和日期类型 数值型①整数型1 2 3 4 81bin表示1位,1Byte表示一个字节1B=8b.1汉字=2字节(1 word = 2 byte)1字节=8位(1 by ...
- 安装STS报错(一)
安装STS报错 1.具体报错如下 2.报错原因 3.解决办法