一、创建自定义类加载器

package com.example.jvm.classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream; /**
* Created by Think on 2019/6/9.
*/
public class MyTest16 extends ClassLoader{ private String classLoadName; private final String fileExtension = ".class"; public MyTest16(String classLoadName){
super(); //将系统类加载器当做该类加载器的父加载器
this.classLoadName = classLoadName;
} public MyTest16(ClassLoader parent, String classLoadName){
super(parent); //显示指定该类加载器的父加载器器
this.classLoadName = classLoadName;
} @Override
public String toString() {
return "[" + this.classLoadName + "]";
} @Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = this.loadClassData(classLoadName);
return this.defineClass(classLoadName,data, 0, data.length);
} private byte[] loadClassData(String name){
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = null; try{
this.classLoadName = this.classLoadName.replace(".","//");
is = new FileInputStream(new File(name + this.fileExtension));
baos = new ByteArrayOutputStream();
int ch = 0;
while ( -1 != (ch = is.read())){
baos.write(ch);
}
data = baos.toByteArray(); }catch (Exception ex){
ex.printStackTrace();
}finally {
try {
is.close();
baos.close();
}catch (Exception ex){
ex.printStackTrace();
}
} return data; } public static void main(String[] args) throws Exception{
MyTest16 loader1 = new MyTest16("loader1");
test(loader1);
} public static void test(ClassLoader classLoader) throws Exception {
Class<?> clazz = classLoader.loadClass("com.example.jvm.classloader.MyTest1");
Object object = clazz.newInstance();
System.out.println(object); }
}

  打印结果

com.example.jvm.classloader.MyTest1@1540e19d

  

二、完善上一个实例创建的类加载器

命名空间:

每个类加载器都有自己的命名空间,命名空间由该加载器及所有父加载器所加载的类组成。

在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类。

在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类。

public class MyTest16  extends  ClassLoader{

    private String className;

    //目录
private String path; private final String fileExtension = ".class"; public MyTest16(String classLoadName){
super(); //将系统类加载器当做该类加载器的父加载器
this.className = classLoadName;
} public MyTest16(ClassLoader parent, String classLoadName){
super(parent); //显示指定该类加载器的父加载器器
this.className = classLoadName;
} public void setPath(String path) {
this.path = path;
} @Override
public String toString() {
return "[" + this.className + "]";
} @Override
protected Class<?> findClass(String clasName) throws ClassNotFoundException {
System.out.println("findClass invoked:" + clasName);
System.out.println("class loader name: " + this.className);
byte[] data = this.loadClassData(clasName);
return this.defineClass(clasName,data, 0, data.length);
} private byte[] loadClassData(String className){
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = null; try{
className = className.replace(".","//");
System.out.println("className11:" +this.className);
is = new FileInputStream(new File(this.path + className + this.fileExtension));
baos = new ByteArrayOutputStream();
int ch = 0;
while ( -1 != (ch = is.read())){
baos.write(ch);
}
data = baos.toByteArray(); }catch (Exception ex){
ex.printStackTrace();
}finally {
try {
is.close();
baos.close();
}catch (Exception ex){
ex.printStackTrace();
}
} return data; } public static void main(String[] args) throws Exception{
MyTest16 loader1 = new MyTest16("loader1");
//loader1.setPath("D:/workspace/study/ jvm_demo/build/classes/java/main/");
loader1.setPath("D:/temp/"); // 将 D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/classloader MyTest1文件移动到 D:/temp/com/example/jvm/classloader目录下
Class<?> clazz = loader1.loadClass("com.example.jvm.classloader.MyTest1"); //
System.out.println("class:" + clazz.hashCode());
Object object = clazz.newInstance();
System.out.println(object);
//System.out.println(object.getClass().getClassLoader()); MyTest16 loader2 = new MyTest16("loader2");
loader2.setPath("D:/temp/");
Class<?> clazz2 = loader2.loadClass("com.example.jvm.classloader.MyTest1"); //
System.out.println("class2:" + clazz2.hashCode());
Object object2 = clazz2.newInstance();
System.out.println(object2); } }

  将 D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/classloader  MyTest1文件移动到 D:/temp/com/example/jvm/classloader目录下

打印结果:

findClass invoked:com.example.jvm.classloader.MyTest1
class loader name: loader1
className11:loader1
class:21685669
com.example.jvm.classloader.MyTest1@7f31245a findClass invoked:com.example.jvm.classloader.MyTest1
class loader name: loader2
className11:loader2
class2:1173230247
com.example.jvm.classloader.MyTest1@330bedb4

  1)loader1 和loader2 是两个实例,构成了两个不同的命名空间。

此时使用的是自定义类加载器。两个类的hascode值是不一样的。

2)如果将D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/classloader  MyTest1文件不移除,

打印的结果:

class:356573597
com.example.jvm.classloader.MyTest1@677327b6 class2:356573597
com.example.jvm.classloader.MyTest1@14ae5a5

  两个列的hasCode值是一样的,是同一个值。使用的类加载器是APP类加载器。 因为测试,父加载器会加载D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/classloader的MyTest1.class 文件,加载到了。自定义类加载器就不需要在加载了。

三、在二的基础上进行改造

package com.example.jvm.classloader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream; /**
* Created by Think on 2019/6/9.
*/
public class MyTest16 extends ClassLoader{ private String className; //目录
private String path; private final String fileExtension = ".class"; public MyTest16(String classLoadName){
super(); //将系统类加载器当做该类加载器的父加载器
this.className = classLoadName;
} public MyTest16(ClassLoader parent, String classLoadName){
super(parent); //显示指定该类加载器的父加载器器
this.className = classLoadName;
} public void setPath(String path) {
this.path = path;
} @Override
public String toString() {
return "[" + this.className + "]";
} @Override
protected Class<?> findClass(String clasName) throws ClassNotFoundException {
System.out.println("findClass invoked:" + clasName);
System.out.println("class loader name: " + this.className);
byte[] data = this.loadClassData(clasName);
return this.defineClass(clasName,data, 0, data.length);
} private byte[] loadClassData(String className){
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = null; try{
className = className.replace(".","//");
//System.out.println("className:" +this.className);
is = new FileInputStream(new File(this.path + className + this.fileExtension));
baos = new ByteArrayOutputStream();
int ch = 0;
while ( -1 != (ch = is.read())){
baos.write(ch);
}
data = baos.toByteArray(); }catch (Exception ex){
ex.printStackTrace();
}finally {
try {
is.close();
baos.close();
}catch (Exception ex){
ex.printStackTrace();
}
} return data; } public static void main(String[] args) throws Exception{
MyTest16 loader1 = new MyTest16("loader1");
//loader1.setPath("D:/workspace/study/ jvm_demo/build/classes/java/main/");
loader1.setPath("D:/temp/"); //删除 将 D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/classloader MyTest1文件移动到 D:/temp/com/example/jvm/classloader目录下
Class<?> clazz = loader1.loadClass("com.example.jvm.classloader.MyTest1"); //
System.out.println("class:" + clazz.hashCode());
Object object = clazz.newInstance();
System.out.println(object);
System.out.println(); MyTest16 loader2 = new MyTest16(loader1,"loader2");
loader2.setPath("D:/temp/");
Class<?> clazz2 = loader2.loadClass("com.example.jvm.classloader.MyTest1"); //
System.out.println("class:" + clazz2.hashCode());
Object object2 = clazz2.newInstance();
System.out.println(object2); } }

  删除工程里的MyTest1.class,保留D:\temp 目录下的MyTest1.class 文件。

设置MyTest16 loader2 = new MyTest16(loader1,"loader2");

输出结果如下:

findClass invoked:com.example.jvm.classloader.MyTest1
class loader name: loader1
class:21685669
com.example.jvm.classloader.MyTest1@7f31245a class:21685669
com.example.jvm.classloader.MyTest1@6d6f6e28

  hashCode值都是21685669

MyTest1由自定义loader1加载,

loader2委托loader1加载,loader1已经加载过了MyTest类,所以loader2不需要加载了。

四、在三的基础上进行改造

 public static void main(String[] args)  throws Exception{
MyTest16 loader1 = new MyTest16("loader1");
//loader1.setPath("D:/workspace/study/ jvm_demo/build/classes/java/main/");
loader1.setPath("D:/temp/");
Class<?> clazz = loader1.loadClass("com.example.jvm.classloader.MyTest1"); //
System.out.println("class:" + clazz.hashCode());
Object object = clazz.newInstance();
System.out.println(object);
System.out.println(); MyTest16 loader2 = new MyTest16(loader1,"loader2");
loader2.setPath("D:/temp/");
Class<?> clazz2 = loader2.loadClass("com.example.jvm.classloader.MyTest1"); //
System.out.println("class:" + clazz2.hashCode());
Object object2 = clazz2.newInstance();
System.out.println(object2);
System.out.println(); MyTest16 loader3 = new MyTest16(loader2,"loader3");
loader3.setPath("D:/temp/");
Class<?> clazz3 = loader3.loadClass("com.example.jvm.classloader.MyTest1"); //
System.out.println("class:" + clazz3.hashCode());
Object object3 = clazz3.newInstance();
System.out.println(object3);
System.out.println(); }

 删除工程下的的MyTest1.class,保留D:\temp 下的MyTest1.class文件, 打印结果

findClass invoked:com.example.jvm.classloader.MyTest1
class loader name: loader1
class:21685669
com.example.jvm.classloader.MyTest1@7f31245a class:21685669
com.example.jvm.classloader.MyTest1@6d6f6e28 class:21685669
com.example.jvm.classloader.MyTest1@135fbaa4

  

JVM 自定义类加载器的更多相关文章

  1. JVM自定义类加载器加载指定classPath下的所有class及jar

    一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...

  2. (转)JVM——自定义类加载器

    背景:为什么要自定义,如何自定义,实现过程 转载:http://blog.csdn.net/SEU_Calvin/article/details/52315125 0. 为什么需要自定义类加载器 网上 ...

  3. JVM——自定义类加载器

    )以上两种情况在实际中的综合运用:比如你的应用需要通过网络来传输 Java 类的字节码,为了安全性,这些字节码经过了加密处理.这个时候你就需要自定义类加载器来从某个网络地址上读取加密后的字节代码,接着 ...

  4. JVM 自定义类加载器在复杂类情况下的运行分析

    一.自定义类加载器在复杂类情况下的运行分析 1.使用之前创建的类加载器 public class MyTest16 extends ClassLoader{ private String classN ...

  5. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  6. jvm(1)类的加载(二)(自定义类加载器)

    [深入Java虚拟机]之四:类加载机制 1,从Java虚拟机的角度,只存在两种不同的类加载器: 1,启动类加载器:它使用C++实现(这里仅限于Hotspot,也就是JDK1.5之后默认的虚拟机,有其他 ...

  7. JVM之类加载器下篇

    除了自定义的类加载之外,jvm存在三种类加载器,并以一种父委托的加载机制进行加载. --启动类加载器,又称根加载器,是一个native的方法,使用c++实现.在java中我们用null标识,用于加载j ...

  8. java类加载器学习2——自定义类加载器和父类委托机制带来的问题

    一.自定义类加载器的一般步骤 Java的类加载器自从JDK1.2开始便引入了一条机制叫做父类委托机制.一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载,父类调用父类的父类,一直到顶级类加载 ...

  9. 【深入理解JVM】类加载器与双亲委派模型

    原文链接:http://blog.csdn.net/u011080472/article/details/51332866,http://www.cnblogs.com/lanxuezaipiao/p ...

随机推荐

  1. java线程的生命周期及五种基本状态

    一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程各重要知识点.掌握了上图中的各知识点,Java中的多线程也就基本上掌 ...

  2. go工程组织规范

    go编码以workspace形式管理,一个workspace包含所有的Go编码,包含多个版本控制仓库(例如使用git管理的多个仓库).每个仓库包含多个包package,每个package是一个单独的路 ...

  3. [openssl][nginx] 使用openssl模拟ssl/tls客户端测试nginx stream

    一 server的配置 nginx # cat conf/nginx.conf daemon off; events { debug_connection ; } stream { upstream ...

  4. 微信小程序API~用户信息

    UserInfo 用户信息 属性 string nickName 用户昵称 string avatarUrl 用户头像图片的 URL.URL 最后一个数值代表正方形头像大小(有 0.46.64.96. ...

  5. 《团队名称》第九次团队作业:Beta冲刺与验收准备

    项目 内容 这个作业属于哪个课程 软件工程 这个作业的要求在哪里 实验十三 团队作业9:Beta冲刺与团队项目冲刺 团队名称 发际线总和我作队 作业学习目标 (1)掌握软件黑盒测试技术:(2)掌握软件 ...

  6. faster-rcnn在ubuntu16.04环境下的超级详细的配置(转)

    首先,下载好必须要的安装包.为了方便,我已经全部上传在了百度云. - ubuntu16.04系统 链接:http://pan.baidu.com/s/1geU8piz 密码:25mk - cuda8. ...

  7. Go语言 - 关于常用插件不能安装的处理办法

    解决办法 这里的是Windows的环境下的解决办法 在GOPATH的src目录下面创建github.com\golang文件夹,若文件夹存请忽略本步骤 在vs code终端执行: cd %GOPATH ...

  8. Mysql 基础 1

    MySQL基础 1.概念 数据库,为我们提供高效.便捷的方式对数据进行增删改查的工具 优势 程序稳定.数据一致性.并发.效率 2.数据库管理系统 (DataBase Management System ...

  9. 【CSS3】 新增属性

    一. box-shadow(阴影效果) 使用: box-shadow: 20px 10px 0 #000; -moz-box-shadow: 20px 10px 0 #000; -webkit-box ...

  10. zeebe 集成elasticsearch exporter && 添加operate

    zeebe 的operate是一个功能比较强大的管理工具,比simple-monitor 有好多方面上的改进 安全,支持用户账户的登陆 界面更友好,界面比较符合开团队工作流引擎的界面 系统监控更加强大 ...