用.class文件创建对象
第一步: 给你一个编译好的class文件以及它的包名,创建一个对象出来。
1)class文件源代码
- package com.wsc.classloader;
- public class Tool{
- public void print() {
- }
- }
2)使用javac Tool.java 编译成class文件
3)将Tool.class文件读取到内存中,生成byte[]数组
- /**
- * 加载class文件
- *
- * @param clazzPath
- * class绝对文件路径
- * @return 字节数组
- * @throws IOException
- */
- private byte[] loadClassFile(String clazzPath) throws IOException {
- FileInputStream fis = new FileInputStream(clazzPath);
- BufferedInputStream bis = new BufferedInputStream(fis);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buffer = new byte[1024 * 256];
- int ch = 0;
- while ((ch = bis.read(buffer, 0, buffer.length)) != -1) {
- baos.write(buffer, 0, ch);
- }
- return baos.toByteArray();
- }
4)自定义ClassLoader,使用ClassLoader中的defineClass方法:protected final Class<?> defineClass(String name, byte[] b, int off, int len)。参数分别是类名称,class文件对应的字节数组,起始位置和终止位置。
- @Override
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
- Class<?> c = findLoadedClass(name);
- if (c == null) {
- c = defineClass(name, data, 0, data.length);
- }
- return c;
- }
整体代码是:
- package com.wsc.classloader;
- import java.io.BufferedInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.FileInputStream;
- import java.io.IOException;
- public class ClassLoaderOne extends ClassLoader {
- public static void main(String[] args) throws Exception {
- ClassLoaderOne loader = new ClassLoaderOne(
- "E:\\JAVA\\JAVAFX\\ClassLoader\\libs\\Tool.class");
- Class<?> clazz = loader.loadClass("com.wsc.classloader.Tool");
- Object o = clazz.newInstance();
- System.out.println(o.getClass().getClassLoader());
- }
- private byte[] data;
- public ClassLoaderOne(String clazzPath) throws IOException {
- data = loadClassFile(clazzPath);
- }
- /**
- * 加载class文件
- *
- * @param clazzPath
- * class绝对文件路径
- * @return 字节数组
- * @throws IOException
- */
- private byte[] loadClassFile(String clazzPath) throws IOException {
- FileInputStream fis = new FileInputStream(clazzPath);
- BufferedInputStream bis = new BufferedInputStream(fis);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buffer = new byte[1024 * 256];
- int ch = 0;
- while ((ch = bis.read(buffer, 0, buffer.length)) != -1) {
- baos.write(buffer, 0, ch);
- }
- return baos.toByteArray();
- }
- @Override
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
- Class<?> c = findLoadedClass(name);
- if (c == null) {
- c = defineClass(name, data, 0, data.length);
- }
- return c;
- }
- }
感觉是这样的,跑一下:
- Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang
- at java.lang.ClassLoader.preDefineClass(Unknown Source)
- at java.lang.ClassLoader.defineClass(Unknown Source)
- at java.lang.ClassLoader.defineClass(Unknown Source)
- at com.wsc.classloader.ClassLoaderOne.loadClass(ClassLoaderOne.java:52)
- at java.lang.ClassLoader.loadClass(Unknown Source)
- at java.lang.ClassLoader.defineClass1(Native Method)
- at java.lang.ClassLoader.defineClass(Unknown Source)
- at java.lang.ClassLoader.defineClass(Unknown Source)
- at com.wsc.classloader.ClassLoaderOne.loadClass(ClassLoaderOne.java:52)
- at java.lang.ClassLoader.loadClass(Unknown Source)
- at com.wsc.classloader.ClassLoaderOne.main(ClassLoaderOne.java:14)
意思是:禁止加载名为java.lang的包。
原因是:虽然Tool类中没有使用任何引入java.lang下类,但是它的父类Object是在java.lang下的,classloader加载Tool类时会把它所有的关系网都加载出来才行,父类Object肯定是要加载的。
这样就简单了!无非多写一个If else.使用父加载器(类加载器都有一个父类加载器)加载即可。
- @Override
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
- Class<?> c = findLoadedClass(name);
- if (name.equals("java.lang.Object")) {
- ClassLoader parent = getParent();
- c = parent.loadClass(name);
- }
- if (c == null) {
- c = defineClass(name, data, 0, data.length);
- }
- return c;
- }
跑一下结果是:
- com.wsc.classloader.ClassLoaderOne@ca470
第二步:新的问题
- Method[] methods = clazz.getMethods();
- for (int i = 0; i < methods.length; i++) {
- String name = methods[i].getName();
- System.out.println(name);
- Class<?>[] params = methods[i].getParameterTypes();
- for (int j = 0; j < params.length; j++) {
- System.out.println(params[j].toString());
- }
- }
这个时候还是会报刚才的错误,因为Method类也在java.lang包下,只能在增加一个If else.
显然,代码应该这样写
- @Override
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
- Class<?> c = findLoadedClass(name);
- if (c == null) {
- // 如果父加载器不为null,使用父类加载器加载(比如Object,HashMap等核心类)
- if (getParent() != null) {
- try {
- c = getParent().loadClass(name);
- } catch (Exception e) {
- // 父类可能没加载,则抛异常
- }
- }
- // 如果父类加载器没有加载,再使用自定义加载器加载
- if (c == null) {
- c = defineClass(name, data, 0, data.length);
- }
- }
- return c;
- }
打印结果:
- toString
- class java.lang.String
- getClass
- hashCode
- equals
- class java.lang.Object
- notify
- notifyAll
- wait
- long
- int
- wait
- wait
- long
- com.wsc.classloader.ClassLoaderOne@fcfa52
第三步:如果本地可以通过.class文件创建,远程当然也已同一个道理(如果需要加密,在本地多一个解密即可)。如果class文件是远程调用的话,本地一般使用接口或者反射两种方法调用。首选是接口,反射一是效率,而是要清楚所有的方法名称、参数名称过于麻烦。
由于远程加载class文件到本地,如果出错很难定位出错位置。幸好,classloader使用规则默认是根据URLClassLoader来使用的,会先根据检查本地是否有该类,所以可以直接将源码放在本地即可调试,当然发布的时候一定要删除。
如图:
通过这个基本的入门程序可以了解ClassLoader的基本流程。
1
用.class文件创建对象的更多相关文章
- 大三上 —— IOS五天实训
第二天: 注册使用xib:1.首先为xib文件创建对象--let nib = UINib(nibName: "xib文件名", bundle: nil).2.具体的控件注册该xib ...
- xib与nib的区别
xib和nib都是Interface Builder的图形界面设计文档,nib这个名字来自于NeXTSTEP系统,在NeXTSTEP被Apple收购之前,一直使用nib作为Interface Buil ...
- 十七、EnterpriseFrameWork框架核心类库之Web控制器
回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U EFW框架中的WebContro ...
- VBS基础篇 - wscript 对象
一.wscript对象 描述:提供对 Windows 脚本宿主对象模型根对象的访问.详述:WScript 对象是 Windows 脚本宿主对象模型层次结构的根对象.它可在任何脚本文件中使用,不需要特定 ...
- 【转】基于RMAN实现坏块介质恢复(blockrecover)
本文转自:乐沙弥的世界 对于物理损坏的数据块,我们可以通过RMAN块介质恢复(BLOCK MEDIA RECOVERY)功能来完成受损块的恢复,而不需要恢复整个数据库或所有文件来修复这些少量受损的数据 ...
- java反射知识
java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称 ...
- 我用Cocos2d-x模拟《Love Live!学院偶像祭》的Live场景(二)
上一章分析了Live场景中各个元素的作用,这一章开始来分析最关键的部分——打击物件的实现. 上一章放出的视频很模糊,先来看一个清晰版的复习一下:http://www.bilibili.com/vide ...
- 【Unity 3D 游戏开发】Unity3D 入门 - 工作区域介绍 与 入门示例
一. 工作区域详解 1. Scence视图 (场景设计面板) scence视图简介 : 展示创建的游戏对象, 可以对所有的游戏对象进行 移动, 操作 和 放置; -- 示例 : 创建一个球体, 控制摄 ...
- OC语言大总结(上)
根据OC学习的知识点,总结了一下,希望能帮到大家! 作者:韩俊强 未经允许,请勿转载! 关注博主:http://weibo.com/hanjunqiang 第一节类于对象 类与对象http:// ...
随机推荐
- 那些年被我坑过的Python——邂逅与初识(第一章)
第一问:为什么学习Python? 虚妖说:为了还债,还技术债,很早接触编程,却一直徘徊,也码了很多代码,却从未真真学会编程! 第二问:什么是Python 是一种以简洁.优雅著称的解释型.动态.强类型的 ...
- VS下面的编译错误-----转换到 COFF 期间失败: 文件无效或损坏
最近写了一个vs的小项目,然后编译的时候vs提示了"转换到 COFF 期间失败: 文件无效或损坏"的问题. 去网上搜索了一个解决方案.原作者的链接是:http://jingyan. ...
- HTML5之一HTML5简介
1.什么是HTML5? HTML5是HTML的新一代标准.以前版本的HTML标准4.01发布于1999. 自1999年以后,web已经有了翻天覆地的变化. 实际上HTML5仍旧是开发中的一个标准.但是 ...
- 玩转C++运算符重载
运算符重载语法:返回值类型 operator运算符(参数列表) { 代码逻辑... } C++中的运算符重载是通过函数来实现的,可以将重载的运算符看作是类成的一个成员函数,向普通函数一样调用.如重 ...
- [BZOJ 1098] [POI2007] 办公楼biu 【链表优化BFS】
题目链接:BZOJ - 1098 题目分析 只有两个点之间有边的时候它们才能在不同的楼内,那么就是说如果两个点之间没有边它们就一定在同一座楼内. 那么要求的就是求原图的补图的连通块. 然而原图的补图的 ...
- Hibernate 使用注解后没发现建表
可能的原因: ①该注解类中的注解出错:例如是否因为属性名与数据库关键字冲突 ②是否添加包扫描配置: <property name="packagesToScan" value ...
- vim文本编辑器的总结
说起文本编辑器,在下就不得不说vim这个老古董了,说老吧,但也是老当益壮,至今还是有不少拥护者.的确,vim很实用,在下就先列出vi的优点吧. 1.如果精通了vim,就可以省去鼠标了. 2.vim是跨 ...
- MFC窗口风格 WS_style/WS_EX_style(超详细)
窗口风格(Window style) WS_BORDER 有边框窗口 WS_CAPTION 必须和WS_BORDER风格配合,但不能与WS_DLGFRAME风格一起使用.指示窗口包含标题要部分 ...
- 3.1日 重温JVM相关信息
1.JDK.JRE.JVM的关系: JDK是java开发的必备工具箱,JDK其中有一部分是JRE,JRE是JAVA运行环境,JVM则是JRE最核心的部分. 2.JVM的组成: JVM由4大部分组成:C ...
- ajax post data 获取不到数据,注意 content-type的设置
ajax post data 获取不到数据,注意 content-type的设置 .post/get关于 jQuery data 传递数据.网上各种获取不到数据,乱码之类的.好吧今天我也遇到了,网 ...