`
十三月的
  • 浏览: 168805 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

用.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
print
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的基本流程。
    

   

 

  • 大小: 10.9 KB
5
0
分享到:
评论
9 楼 十三月的 2014-08-05  
yun900800 写道
哦,,删掉之后Ok了,是因为会先加载classpath下的类吗?

恩 是滴
8 楼 yun900800 2014-08-04  
哦,,删掉之后Ok了,是因为会先加载classpath下的类吗?
7 楼 十三月的 2014-08-02  
yun900800 写道
麻烦看看啥问题啊?

我用你的代码测试了一下,打印的是:
setUserName
class java.lang.String
hekai
getUserName
getClass
hashCode
equals
class java.lang.Object
toString
notify
notifyAll
wait
long
int
wait
wait
long
com.hk.chapter11.baseinfo.ClassLoaderOne@18b81e3


你一定要把ClassLoaderCatr类删除掉或者改名字,否则会先加载本地的。如果还有问题加我QQ:1049321577
6 楼 wodelaop 2014-08-01  
12312312333333333333333333333
5 楼 yun900800 2014-08-01  
麻烦看看啥问题啊?
4 楼 yun900800 2014-08-01  
public class ClassLoaderCat {

private String userName;

/**
* @return the userName
*/
public String getUserName() {
return userName;
}

/**
* @param userName the userName to set
*/
public void setUserName(String userName) {
this.userName = userName;
}



}
3 楼 yun900800 2014-08-01  
就是在第二步出的问题

这个是我的代码:

public class ClassLoaderOne extends ClassLoader {

private byte[] data;

private byte[] loadClassFile(String classPath) throws IOException {
FileInputStream in = new FileInputStream(classPath);

BufferedInputStream bis = new BufferedInputStream(in);

ByteArrayOutputStream bs = new ByteArrayOutputStream();

byte[] buffer = new byte[2048];
int ch = 0;
while ((ch = bis.read(buffer, 0, buffer.length)) != -1) {
bs.write(buffer, 0, ch);
}
return bs.toByteArray();
}

public ClassLoaderOne(String clazzPath) throws IOException {
data = loadClassFile(clazzPath);
}

protected Class<?> loadClass(String classnName, boolean resolve)
throws ClassNotFoundException {
Class<?> c = findLoadedClass(classnName);
if (c == null) { 
        // 如果父加载器不为null,使用父类加载器加载(比如Object,HashMap等核心类) 
        if (getParent() != null) { 
            try { 
                c = getParent().loadClass(classnName); 
            } catch (Exception e) { 
                // 父类可能没加载,则抛异常 
            } 
 
        } 
        // 如果父类加载器没有加载,再使用自定义加载器加载 
        if (c == null) { 
            c = defineClass(classnName, data, 0, data.length); 
        } 
    }   
    return c; 
}

/**
* @param args
*/
public static void main(String[] args) throws Exception {
ClassLoaderOne loader = new ClassLoaderOne( 
                "E:\\ClassLoaderCat.class"); 
        Class<?> clazz = loader.loadClass("com.hk.chapter11.baseinfo.ClassLoaderCat"); 
        Object o = clazz.newInstance(); 
        Method[] methods = clazz.getMethods(); 
        for (int i = 0; i < methods.length; i++) { 
            String name = methods[i].getName();
            if (name.equals("setUserName")) {
            methods[i].invoke(o, "hekai");
            }
            if (name.equals("getUserName")) {
            System.out.println(methods[i].invoke(o));
            }
            System.out.println(name);
            Class<?>[] params = methods[i].getParameterTypes(); 
            for (int j = 0; j < params.length; j++) { 
                System.out.println(params[j].toString()); 
            } 
        } 
        System.out.println(o.getClass().getClassLoader());            
}

}
2 楼 十三月的 2014-07-31  
yun900800 写道
改成

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); 
        } 
    } 

后的类加载器怎么是sun.misc.Launcher$AppClassLoader@addbf1


如果是第二步,不会产生你说的这种情况,我有结果打印
除非是第三种情况,你把Tool类放在了本地,此时会优先加载本地代码,加载本地代码的classloader是AppClassLoader
1 楼 yun900800 2014-07-31  
改成

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); 
        } 
    } 

后的类加载器怎么是sun.misc.Launcher$AppClassLoader@addbf1

相关推荐

    Java如何修改.class文件变量

    在示例代码中,我们创建了一个名为`Test`的类,它读取`HelloWorld.class`文件,然后遍历常量池,找到索引23的`ConstantUtf8Info`对象,并将其值更改为"Hello World HELLO WORLD"。修改完成后,使用`ClassFileWriter`...

    使用Javassist对.class文件进行修改.doc

    1. **ClassPool**: `ClassPool` 类是 Javassist 的核心组件,它管理着一系列的 `CtClass` 对象,这些对象代表了 `.class` 文件。`getDefault()` 方法会返回一个默认的 `ClassPool`,它会从当前的类加载器中获取 `....

    python实现的简单的class解析以及简单执行class.zip

    在本主题中,我们将探讨如何使用Python来解析Java的Class文件,并对其进行简单的执行。这是一项有趣的技术,可以帮助我们理解Java字节码的工作原理,同时也可以在Python环境中运行Java代码。 首先,Java的Class文件...

    C#生成.dat文件

    例如,可以使用`FileStream`类创建一个新的.dat文件,然后通过`BinaryWriter`或`StreamWriter`写入数据。以下是一个基本示例: ```csharp using System.IO; // 创建一个.dat文件 string filePath = "data.dat"; ...

    asp用json类:jsonObject.class.asp

    1. **创建对象**:在ASP中,你可以通过`new`关键字实例化一个`jsonObject`对象,如`set json = new jsonObject`。 2. **添加键值对**:`add`方法用于向JSON对象添加键值对,例如`json.add "key", "value"`。 3. **...

    java编译class文件

    标题“java编译class文件”涉及的核心知识点是Java的编译过程。Java源代码文件的扩展名为`.java`,这些文件包含类定义、方法定义以及其他Java语法元素。要将`.java`文件编译成`.class`文件,我们需要使用Java的JDK...

    class literal & instance.getClass() & Class.forName(String className)

    我们可以使用class literal来获取类的元数据,如类名、接口实现、父类等,也可以用于创建类的新实例(通过`newInstance()`方法,前提是该类有无参构造器)。 接着,我们讨论 "instance.getClass()"。这个方法是每个...

    JDBC.zip_创建数据对象

    3. **创建Statement或PreparedStatement对象**:根据需求选择合适的对象类型,如需动态参数则使用PreparedStatement。 4. **执行SQL语句**:通过Statement或PreparedStatement的executeQuery()或executeUpdate()...

    excel_class.rar

    - 创建新的工作簿:使用`PHPExcel`类实例化一个新的Excel对象。 - 添加工作表:通过`addSheet()`方法向工作簿添加新的工作表。 - 写入单元格数据:使用`setCellValue()`或`setCellValueExplicit()`方法写入单元格...

    jvm解析编译过的class文件

    Java虚拟机(JVM)是Java程序运行的基础,它负责解析和执行编译后的.class文件。这个过程涉及多个阶段,包括加载、验证、准备、解析和初始化。在本篇文章中,我们将深入探讨JVM如何处理.class文件,以及相关工具如何...

    db.class.zip_class

    通过类,我们可以创建对象,这些对象是类的实例,拥有类定义的属性和行为。 在压缩包的文件名称列表中,有一个名为"db.class.php"的文件。这通常包含定义"my db class"的代码,即作者自定义的数据库类。在这个文件...

    corejava.source.class

    这时,可以使用反编译工具(如JAD)将Class文件转换回源代码形式,便于理解和调试。 通过理解和掌握这些知识点,开发者能更好地理解和使用Core Java,从而编写出高效、稳定的Java应用程序。无论是初学者还是经验...

    输出JDK和CGLib动态代理产生的class文件.zip

    在Java编程中,动态代理是一种强大的技术,它允许我们在运行时创建对象的代理,以便在调用实际方法之前或之后执行额外的操作。本压缩包文件提供了两个示例项目,分别展示了JDK动态代理和CGLib动态代理的实现,帮助...

    AnyFo - Util - DynaObject :专门创建动态对象的工具

    那么,如果要在程序退出之前能动态的实时 加载修改后编译出来的新的.class文件中的效果,则需要创建动态对象,如同Tomcat中的热部署效果一样。 于是,专门创建动态对象的工具包DynaObject产生了。 DynaObject...

    Java中Class类工作原理详解

    换言之,每当编写并且编译了一个新类,就会产生一个Class对象(恰当地说,是被保存在一个同名的.class文件中)。在运行时,当我们想生成这个类的对象时,运行这个程序的 Java虚拟机(JVM)首先检查这个类的Class对象...

    Java中Class对象详解.docx

    如果已经加载,则根据`.class`文件创建实例对象。 2. **单例性**:通过不同的方式生成的`Class`对象实际上是指向同一个`Class`实例。这意味着即使使用不同的方法获取`Class`对象,也只会存在一个`Class`实例。 3. ...

    SqlModel.class-易语言.zip

    开发者可以通过创建PreparedStatement对象来执行预编译的SQL语句,或者通过Statement对象来执行基本的SQL命令。 描述中的".zip"和".rar"都是常见的文件压缩格式,它们用于将多个文件或目录打包成一个单一的文件,...

    qt通过类名动态创建对象

    4. **动态创建对象**:有了类名后,我们可以使用`QMetaObject::newInstance`来动态创建对象。这个函数接受一个类型ID或类名字符串作为参数,返回一个`QObject`指针。如果类没有继承自`QObject`,则无法使用此方法。 ...

    java四种创建对象的方式

    通过反射创建对象时,可以使用Class类的newInstance()方法。但是需要注意的是,这要求Customer类必须有一个默认构造方法,且该方法需要无参。使用反射创建对象的代码示例如下: ```java Class objClass = Class.for...

    JAVA文件中调用已编译的.CLASS的类.doc

    它接受类路径字符串和类名,创建`URL`对象,然后使用自定义类加载器加载类并实例化。 - 实例化后,可以通过类型转换将加载的类强制转换为接口类型,然后调用接口方法。 5. **环境变量与类路径**: - 通常,Java...

Global site tag (gtag.js) - Google Analytics