一个Java Class 对象的一生

一  Java Class文件

     java的class文件是java文件通过javac编译之后得到的jvm可执行的文件,以.class结尾的文件。

二  Java Class 对象的生命周期

      java对象的生命周期如下图所示:

三  类加载器

        上述Java Class对象的生命周期中的第一步,load class的流程里面就是实质上就是java的类加载器加载磁盘上的*.class文件,加载到内存中。类加载器到底是如何工作的呢?下面将来讲解下类加载器。

        java中的类加载器分为四大类:BootStrapClassLoader,   ExtensionClassLoader,  AppClassLoader,  自定义类加载器。       

              BootStrap ClassLoader: 根类加载器, 主要加载的是rt.jar,  charset.jar等相关的jar里面的class

              ExtensionClassLoader: 扩展类加载器, 主要加载java.ext.dirs这个参数所对应的文件里面的.class,例如:D:\Java1.8\jdk1.8.0_191\jre\lib\ext;C:\Windows\Sun\Java\lib\ext

              AppClassLoader:系统类加载器,主要加载应用程序的代码,classpatch目录下的类。、

              自定义类加载器 :  自己设置加载文件的目录。自定义类加载器要继承ClassLoader类,重写findClass方法,findClass中要调用defineClass方法,从而返回一个Class<?>的对象。

       获取类加载器的代码如下所示:

package zd.classLoader;

import java.net.URL;

import zd.hash.HashTest;

public class ClassLoaderTest {
	
	public static void main(String[] args){
		//HashTest是我们代码里面写的类, HashTest.class.getClassLoader()//获取到加载我们自己写的类的类加载器
		ClassLoader appLoad= HashTest.class.getClassLoader();
		//输出类加载器为sun.misc.Launcher$AppClassLoader@73d16e93,由此可见,我们写的业务代码的类加载器是AppClassLoader这个类加载器加载到内存中去的
		System.out.println(appLoad);
		
		//获取类加载器sun.misc.Launcher$AppClassLoader的父类加载器sun.misc.Launcher$ExtClassLoader(需要特殊说明的是AppClassLoader和ExtClassLoader并不存在继承关系)
		ClassLoader extLoad= HashTest.class.getClassLoader().getParent();
	    System.out.println(extLoad);
	    //获取到ExtClassLoader类加载器要加载的目录,输出为D:\Java1.8\jdk1.8.0_191\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
	    //表明ExtClassLoader类加载器获取加载上述目录中的所有的jar里面的.class文件
	    String extDirs = System.getProperty("java.ext.dirs");
	    System.out.println(extDirs);
	    
	    //获取到根类加载器要加载的资源内容
	    //输出结果如下
	    //file:/D:/Java1.8/jdk1.8.0_191/jre/lib/resources.jar
	    //file:/D:/Java1.8/jdk1.8.0_191/jre/lib/rt.jar
	    //file:/D:/Java1.8/jdk1.8.0_191/jre/lib/sunrsasign.jar
	    //file:/D:/Java1.8/jdk1.8.0_191/jre/lib/jsse.jar
	    //file:/D:/Java1.8/jdk1.8.0_191/jre/lib/jce.jar
	    //file:/D:/Java1.8/jdk1.8.0_191/jre/lib/charsets.jar
	    //file:/D:/Java1.8/jdk1.8.0_191/jre/lib/jfr.jar
	    //file:/D:/Java1.8/jdk1.8.0_191/jre/classes
	    URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
		for(URL url : urls){
			System.out.println(url.toString());
		}
	    
	    
	}

}

             自定义类加载器代码如下:  自定义类加载器的代码比较简单,这里我就不过多说明了

package zd.classLoader;

import java.lang.reflect.Method;

public class MyClassLoadMain {
	
	public static void main(String[] args){
		MyClassLoderTest test = new MyClassLoderTest();
		try {
			Class<?> cls = test.findClass("zd.classLoader.Test");
			Method[] methords = cls.getDeclaredMethods();
			Object o = cls.newInstance();
			for(Method m : methords){
				if(m.getParameterCount() == 0){
					System.out.println(m.invoke(o, null));
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}


package zd.classLoader;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class MyClassLoderTest extends ClassLoader {
	
	@Override
	public Class<?> findClass(String name) throws ClassNotFoundException{
		String namePath = name.replaceAll("\\.", "\\\\");
		File file = new File("D:\\"+File.separator+namePath+".class");
		ByteArrayOutputStream os = null;
		InputStream is = null;
		try {
		    is = new FileInputStream(file);
			os = new ByteArrayOutputStream();
			int length = 0;
			byte[] bytes = new byte[1024];
			while((length = is.read(bytes)) != -1){
				os.write(bytes, 0, length);
			}
			byte[] classBytes = os.toByteArray();
			return defineClass(name, classBytes, 0, classBytes.length);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try{
				if(os != null){
					os.close();
				} 
				if(is != null){
					is.close();
				}
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		
		return super.findClass(name);
	}

}


package zd.classLoader;

public class Test {
	
	private static String a = "123";

	public static String getA() {
		return a;
	}

	public static void setA(String a) {
		Test.a = a;
	}
	
	

}

       类加载器是属于双亲委派的方式去加载对应的class文件的。首先AppClassLoader去加载class文件的时候,先去缓存中找(已经加载进去了的class), 如果没有,则去让父加载器找,也就是ExtClassLoader类加载器,父类加载器也从自己的缓存中去查找,如果没有, 再去让父类加载器加载, 也就是BootStrapClassLoader,BootStrapClassLoader的缓存中没有,则到其应该加载的class的目录中去找,如果没有,再委派给子类加载器ExtClassLoader。ExtClassLoader也去其应该加载的class的目录中去找,如果没有,再委托给其子类加载器AppClassLoader. 如果AppClassLoader 没有找到,则抛出ClassNotFoundException。ClassLoader的类加载示意图如下所示:

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值