Class 类加载器,内部类加载实验

原创 2015年11月21日 15:03:19

最近实验通过jdk编译后的Class多出一个内部类class文件,美元$符号的class文件,如A.class ,A$B.class,加载A.class总是报错。

除了加载内部类方法,还有就是把class文件打包成jar,通过自定义URLClassLoader  加载jar文件,做类似与Osgi的工作。

通过类加载器,做一个动态加载模块的应用服务器。


通过网上找到代码例子改改后解决现在的问题。


Exception in thread "main" java.lang.LinkageError: loader constraint violation: when resolving method "com.lw.loader.TestClass$TestInnerClass.<init>(Lcom/lw/loader/TestClass;)V" the class loader (instance of com/lw/loader/DynamicClassLoader) of the current class, com/lw/loader/TestClass, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for resolved class, com/lw/loader/TestClass$TestInnerClass, have different Class objects for the type tClass;)V used in the signature
	at com.lw.loader.TestClass.<init>(TestClass.java:12)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
	at java.lang.Class.newInstance(Class.java:374)
	at com.lw.loader.DynamicClassLoaderTest.main(DynamicClassLoaderTest.java:17)


类加载器 重写findClass,通过defineClass写入二进制定义Class类

package com.lw.loader;

import java.io.File;
import java.io.FileInputStream;
import java.util.Hashtable;
import java.util.jar.Manifest;

public class DynamicClassLoader extends ClassLoader {
	private Manifest manifest;
	private Hashtable<String, ClassInfo> classInfo = new Hashtable<String, ClassInfo>();

	/**
	 * Provide delegation constructor
	 */
	DynamicClassLoader(ClassLoader parent) {
		super(parent);
	}

	/**
	 * Same old ClassLoader constructor
	 */
	DynamicClassLoader() {
		super();
	}

	private String getClassPath(String className) {
		String relativeClassPath = className.replace('.', File.separatorChar) + ".class";

		String classPath;
		try {
			classPath = ClassLoader.getSystemResource(relativeClassPath).toURI().getPath().substring(1);
			
			System.out.println(classPath);
			if ((new File(classPath)).exists())
				return classPath;
		} catch (java.net.URISyntaxException e) {
		}

		return null;
	}

	/**
	 * This is the method where the task of class loading is delegated to our custom loader.
	 * 
	 * @param name the name of the class
	 * @return the resulting <code>Class</code> object
	 * @exception ClassNotFoundException if the class could not be found
	 */
	protected Class findClass(String name) throws ClassNotFoundException {
		// get path of given class
		String classPath = getClassPath(name);
		if (classPath == null)
			throw new ClassNotFoundException(name);

		// get last modified time of class file
		File f = new File(classPath);
		long lastModified = f.lastModified();

		// check if given class loaded already
		ClassInfo loadedClassInfo = classInfo.get(name);

		// if class loaded is the newest one, no need to reload it
		if ((loadedClassInfo != null) && (loadedClassInfo.lastModified >= lastModified))
			return loadedClassInfo.classType;

		FileInputStream fi = null;

		try {
			fi = new FileInputStream(f);
			byte[] classBytes = new byte[fi.available()];
			fi.read(classBytes);
			Class result = defineClass(name, classBytes, 0, classBytes.length);
			classInfo.put(name, new ClassInfo(result, lastModified));
			return result;
		} catch (Exception e) {
			// We could not find the class, so indicate the problem with an exception
			e.printStackTrace();
			throw new ClassNotFoundException(name);
		} finally {
			if (null != fi) {
				try {
					fi.close();
				} catch (Exception e) {
				}
			}
		}
	}
}
ClassInfo 信息

package com.lw.loader;

public class ClassInfo {
	public Class classType;
	
	public long lastModified;

	public ClassInfo(Class classType) {
		this.classType = classType;
		this.lastModified = -1;
	}

	public ClassInfo(Class classType, long lastModified) {
		this.classType = classType;
		this.lastModified = lastModified;
	}
}

测试类

package com.lw.loader;

public class TestClass {
	public class TestInnerClass {

		public void printMessage() {
			System.out.println("Test inner info");
		}
	}

	public TestClass() {
		TestInnerClass cls = new TestInnerClass();
	}

	public void printMessage() {
		System.out.println("Test info changed");
	}
}

测试方法

package com.lw.loader;

import java.lang.reflect.Method;

public class DynamicClassLoaderTest {
	public static void main(String[] args) throws Exception {
		while (true) {
			DynamicClassLoader classLoader = new DynamicClassLoader();
			
//			classLoader.findClass("com.lw.loader.TestClass$TestInnerClass"); 
			

			Class c = classLoader.findClass("com.lw.loader.TestClass");

			Method printMessage = c.getMethod("printMessage");

			Object o = c.newInstance();

			printMessage.invoke(o);

			Thread.sleep(5000);
		}
	}
}







版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

Java Class-类-对象 类加载器

声明:本文仅仅是总结学习笔记,使用了以下5篇文章 1.  深入研究java.lang.Class类 (http://wenku.baidu.com/link?url=JYgIYDCKKZ6AOZ3...

一个Java内部类引发的FindNoClass错误

我用java写了一个web服务器,在本地tomcat上测试,没有问题,部署到服务器上,却出现了诡异的500错误。        用Fiddler看了一下,一个Message类出现了FindNoCla...

深入分析ClassLoader工作机制

ClassLoader 较为深入分析。from 加载CLASS到JVM中,审查每个类应该由谁加载,父优先的等级加载机制。加载机制ClassLoader类结构分析ClassLoader抽象类,有很多子类...

内部类的加载时机

内部类是延时加载的,也就是说只会在第一次使用时加载。不使用就不加载,所以可以很好的实现单例模式。 package com.brouth.study.test; public class O...
  • brouth
  • brouth
  • 2016年06月13日 11:47
  • 2490

加载一个类时,其内部类是否同时被加载?静态内部类单例模式

加载一个类时,其内部类是否同时被加载?下面我们做一个实验来看一下。  Java代码   public class Outer {       static {       ...

产生多于的class$1.class的原因

在java中,如果在一个类中定义了内部类,刚会生成:    super&this.class的文件,如果给某个控件添加了Listener事件,则会生成    super&i.class的文件,其中i为...

cocos creatro工程提交到svn遇到的问题

今天我把creator工程提交到svn上面然后同事下载之后页面显示不正常,像这样: 然后在console控制台显示一些黄色的警告: The Asset used by component “c...

深入理解JVM07--虚拟机类加载机制--类加载器、双亲委派模型

本文是基于周志明的《深入理解Java虚拟机》 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部实现,以便让应用程序自己决定如何去获取所...

JVM类加载机制详解(二)类加载器与双亲委派模型

在上一篇JVM类加载机制详解(一)JVM类加载过程中说到,类加载机制的第一个阶段加载做的工作有: 1、通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件)。而...

SE高阶(10):类加载机制—类加载器、类初始化和URLClassLoader

说到类加载就必须得了解JVM(虚拟机)的作用,我们使用eclipse或者命令行调用命令javac.exe运行一个Java程序时,系统会启动虚拟机来加载类,然后运行在虚拟机进程中。加载类的过程的就是类加...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Class 类加载器,内部类加载实验
举报原因:
原因补充:

(最多只允许输入30个字)