热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

java自定义类加载器代码示例

这篇文章主要介绍了java自定义类加载器代码示例,具有一定借鉴价值,需要的朋友可以了解下。

如果要使用自定义类加载器加载class文件,就需要继承java.lang.ClassLoader类。

ClassLoader有几个重要的方法:

protectedClassLoader(ClassLoaderparent):使用指定的、用于委托操作的父类加载器创建新的类加载器。

protectedfinalClass<&#63;>defineClass(Stringname,byte[]b,intoff,intlen):将一个byte数组转换为Class类的实例。

protectedClass<&#63;>findClass(Stringname):使用指定的二进制名称查找类。

publicClass<&#63;>loadClass(Stringname):使用指定的二进制名称来加载类。

protectedfinalClass<&#63;>findLoadedClass(Stringname):如果Java虚拟机已将此加载器记录为具有给定二进制名称的某个类的启动加载器,则返回该二进制名称的类。否则,返回null。

publicfinalClassLoadergetParent():返回委托的父类加载器。

protectedfinalvoidresolveClass(Class<&#63;>c):链接指定的类。

如果要遵循双亲委派模型,则重写findClass(Stringname)方法;如果不想遵循双亲委派模型,则直接重写loadClass(Stringname)方法。

自定义遵循双亲委派模型的类加载器

ParentsDelegateClassLoader.java

package com.zzj.classloader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/** 
 * 双亲委派类加载器,重写findClass(name)方法 
 * 
 * @author Administrator 
 * 
 */
public class ParentsDelegateClassLoader extends ClassLoader {
	private static final String EXT = ".class";
	private String path;
	public ParentsDelegateClassLoader() {
		path = this.getResource("").getPath();
	}
	public ParentsDelegateClassLoader(String path) {
		this.path = path;
	}
	@Override 
	  protected Class<&#63;> findClass(String name) throws ClassNotFoundException {
		byte[] b = null;
		try {
			b = loadClassFile(name);
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		return this.defineClass(name, b, 0, b.length);
	}
	private byte[] loadClassFile(String name) throws IOException {
		String classFile = getClassFile(name);
		System.out.println("即将加载class文件" + classFile);
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		InputStream input = new FileInputStream(classFile);
		int count;
		byte[] temp = new byte[1024];
		while ((count = input.read(temp)) > -1) {
			out.write(temp, 0, count);
		}
		out.close();
		input.close();
		return out.toByteArray();
	}
	private String getClassFile(String name) {
		String pathName = name.replace(".", File.separator);
		if (path.endsWith("/") || path.endsWith("\\")) {
			return path + pathName + EXT;
		}
		return path + File.separator + pathName + EXT;
	}
}

现在类路径classpath下和F:\\ClassloaderTest\\bin目录下都有一个类文件com\zzj\classloader\User.class,包名为com.zzj.classloader,使用类加载器ParentsDelegateClassLoader加载F:\\ClassloaderTest\\bin下的类。

package com.zzj.classloader;
public class App {
	private static final String path = "F:\\ClassloaderTest\\bin";
	private static final String classname = "com.zzj.classloader.User";
	public static void main(String[] args) throws Exception {
		ParentsDelegateClassLoader classLoader = new ParentsDelegateClassLoader(path);
		Class<&#63;> clazz = classLoader.loadClass(classname);
		System.out.println(clazz);
		System.out.println(clazz.getClassLoader());
	}
}

输出:

class com.zzj.classloader.User 
sun.misc.Launcher$AppClassLoader@19821f 

User类的加载器是系统类加载器AppClassLoader,而不是我们自己定义的类加载。实际上被加载不是F:\\ClassloaderTest\\bin下的类,而是classpath下的类。这就是双亲委派模型:当ParentsDelegateClassLoader加载器接收到加载请求后,会先委托给父类加载器,如果父类加载器加载成功,则返回一个Class对象。如果加载失败,才会让接收到加载请求的类加载器加载。

把classpath下的User类删掉测试运行:

即将加载class文件F:\ClassloaderTest\bin\com\zzj\classloader\User.class 
class com.zzj.classloader.User 
com.zzj.classloader.ParentsDelegateClassLoader@61de33 

此时User类的加载为ParentsDelegateClassLoader。

这一点可以从ClassLoader的源码中得到验证:

public Class<&#63;> loadClass(String name) throws ClassNotFoundException { 
  return loadClass(name, false); 
  } 

调用了重载方法:

protected synchronized Class<&#63;> loadClass(String name, boolean resolve) 
  throws ClassNotFoundException 
  { 
  // 先判断该类是否已被当前的类加载器加载 
  Class c = findLoadedClass(name); 
  if (c == null) { 
    try { 
    if (parent != null) {// 如果存在父类加载器,则委派给父类加载 
      c = parent.loadClass(name, false); 
    } else {// 如果父类加载为空,则其父类加载器为引导类加载器 
      c = findBootstrapClass0(name); 
    } 
    } catch (ClassNotFoundException e) { 
      // 如果父类加载器加载失败,则自己加载,调用的就是findClass方法! 
      c = findClass(name); 
    } 
  } 
  if (resolve) { 
    resolveClass(c); 
  } 
  return c; 
  } 

可见,如果想要破坏双亲委派模型,可以直接重写loadClass(Stringname)方法。

自定义不遵循双亲委派模型的类加载器

NotParentsDelegateClassLoader.java

package com.zzj.classloader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
/** 
 * 非双亲委派类加载器,重写loadClass(name)方法 
 * 
 * @author Administrator 
 * 
 */
public class NotParentsDelegateClassLoader extends ClassLoader {
	private static final String EXT = ".class";
	private String path;
	public NotParentsDelegateClassLoader() {
		path = this.getResource("").getPath();
	}
	public NotParentsDelegateClassLoader(String path) {
		this.path = path;
	}
	@Override 
	  public Class<&#63;> loadClass(String name) throws ClassNotFoundException {
		byte[] b = null;
		try {
			b = loadClassFile(name);
		}
		catch (FileNotFoundException e) {
			System.err.println("加载器" + this.getClass().getName() 
			          + "没有找到class文件" + name + ",将委派给父类加载器!");
			// 委派给父类加载器 
			return getClass().getClassLoader().loadClass(name);
		}
		catch (IOException e) {
			System.err.println("加载器" + this.getClass().getName() + "加载class文件" 
			          + name + "失败,将委派给父类加载器!");
			// 委派给父类加载器 
			return getClass().getClassLoader().loadClass(name);
		}
		// 检查该类是否被当前类加载器加载过(只检查当前类加载器,不会检查父类加载器) 
		Class<&#63;> clazz = findLoadedClass(name);
		if (clazz != null) {
			System.out.println("类" + name + "已被加载过!");
			return clazz;
		} else {
			System.out.println("类" + name + "尚未被加载!");
		}
		return this.defineClass(name, b, 0, b.length);
	}
	private byte[] loadClassFile(String name) throws IOException, 
	      FileNotFoundException {
		String classFile = getClassFile(name);
		System.out.println("即将加载class文件" + classFile);
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		InputStream input = new FileInputStream(classFile);
		int count;
		byte[] temp = new byte[1024];
		while ((count = input.read(temp)) > -1) {
			out.write(temp, 0, count);
		}
		out.close();
		input.close();
		return out.toByteArray();
	}
	private String getClassFile(String name) {
		String pathName = name.replace(".", File.separator);
		if (path.endsWith("/") || path.endsWith("\\")) {
			return path + pathName + EXT;
		}
		return path + File.separator + pathName + EXT;
	}
}

现在类路径classpath下有一个类文件com\zzj\classloader\User.class,包名为com.zzj.classloader,使用类加载器NotParentsDelegateClassLoader加载User类。

package com.zzj.classloader;
public class App2 {
	private static final String className = "com.zzj.classloader.User";
	public static void main(String[] args) throws Exception {
		NotParentsDelegateClassLoader classLoader = new NotParentsDelegateClassLoader();
		Class<&#63;> clazz = classLoader.loadClass(className);
		System.out.println(clazz);
		System.out.println(clazz.getClassLoader());
	}
}

输出:

即将加载class文件/E:/Myeclipse/zzjtest/WebRoot/WEB-INF/classes/com\zzj\classloader\User.class 
类com.zzj.classloader.User尚未被加载! 
即将加载class文件/E:/Myeclipse/zzjtest/WebRoot/WEB-INF/classes/java\lang\Object.class 
class com.zzj.classloader.User 
com.zzj.classloader.NotParentsDelegateClassLoader@61de33 
加载器com.zzj.classloader.NotParentsDelegateClassLoader没有找到class文件java.lang.Object,将委派给父类加载器! 

此时User类的加载器是NotParentsDelegateClassLoader,没有先委托给父类,只有加载失败才会委托给父类加载器,正好跟双亲委派模型是反的。

当然,即使加载失败,也可以不委托给父类加载器,而指定其他的类加载器,从而可以构建更加复杂的网状模型的类加载机制

总结

以上就是本文关于java自定义类加载器代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!


推荐阅读
  • 深入理解ExtJS:从入门到精通
    本文详细介绍了ExtJS的功能及其在大型企业前端开发中的应用。通过实例和详细的文件结构解析,帮助初学者快速掌握ExtJS的核心概念,并提供实用技巧和最佳实践。 ... [详细]
  • 本文详细介绍了 Java 中 org.eclipse.jface.viewers.ViewerCell 类的 getBackground() 方法,并提供了多个实际代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 本文探讨了在Java中实现系统托盘最小化的两种方法:使用SWT库和JDK6自带的功能。通过这两种方式,开发者可以创建跨平台的应用程序,使窗口能够最小化到系统托盘,并提供丰富的交互功能。 ... [详细]
  • 本文总结了Java程序设计第一周的学习内容,涵盖语言基础、编译解释过程及基本数据类型等核心知识点。 ... [详细]
  • 本文详细介绍了如何准备和安装 Eclipse 开发环境及其相关插件,包括 JDK、Tomcat、Struts 等组件的安装步骤及配置方法。 ... [详细]
  • 创建项目:Visual Studio Online 入门指南
    本文介绍如何使用微软的 Visual Studio Online(VSO)创建和管理开发项目。作为一款基于云计算的开发平台,VSO 提供了丰富的工具和服务,简化了项目的配置和部署流程。 ... [详细]
  • 探索如何使用公共数据集为您的编程项目提供动力。无论您是编程新手还是有经验的开发者,本文将为您提供实用建议和资源,帮助您启动并运行一个创新的数据驱动型项目。 ... [详细]
  • 本文详细介绍了Ionic框架的使用方法及其与Angular的集成。Ionic框架是一个强大的前端开发工具,适用于构建跨平台的移动应用程序。文章将探讨如何引入必要的CSS和JavaScript文件,并解释bundle.js中包含的核心功能,如路由等。 ... [详细]
  • Git管理工具SourceTree安装与使用指南
    本文详细介绍了Git管理工具SourceTree的安装、配置及团队协作方案,旨在帮助开发者更高效地进行版本控制和项目管理。 ... [详细]
  • Struts与Spring框架的集成指南
    本文详细介绍了如何将Struts和Spring两个流行的Java Web开发框架进行整合,涵盖从环境配置到代码实现的具体步骤。 ... [详细]
  • 在创建新的Android项目时,您可能会遇到aapt错误,提示无法打开libstdc++.so.6共享对象文件。本文将探讨该问题的原因及解决方案。 ... [详细]
  • 本文作者分享了在阿里巴巴获得实习offer的经历,包括五轮面试的详细内容和经验总结。其中四轮为技术面试,一轮为HR面试,涵盖了大量的Java技术和项目实践经验。 ... [详细]
  • 本文详细介绍了如何在Python3环境中配置Appium1.4.6,并指导如何连接模拟器进行自动化测试。通过本文,您将了解从环境搭建到模拟器连接的完整流程。 ... [详细]
  • Eclipse 中 JSP 开发环境配置指南
    本文详细介绍了如何在 Eclipse 集成开发环境中配置 JSP 运行环境,包括必要的软件下载、Tomcat 服务器的配置以及常见问题的解决方法。 ... [详细]
author-avatar
m13380107
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有