java类加载器的知识点总结以及简单实现

一、类加载器的种类

一般分为:引导类加载器(bootstrap classloader)、扩展类加载器(extensions class loader)、应用程序类加载器(application class loader)、自定义类加载器 这4种类加载器

 

一、引导类加载器(bootstrap classloader)

 它用来加载java核心库的(java_home/jre/lib/rt.jar 或者sun.boot.class.path 路径下的内容)是用来原生代码来实现的,并不继承java.lang.classloader,是通过C++来实现。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。

二、扩展类加载器(extensions class loader)

 用来加载java的扩展(java_home/jre/ext/*.jar 或者java.ext.dirs路径下的内容)

 java与虚拟机的实现会提供一个扩展库的目录,该类加载器在此目录里面查找并加载java类

由sun.misc.Launcher$ExtClassLoader实现

三、应用程序类加载器(application class loader)

它根据java引用的类路径(classpath java.class.path路径

一般来说java应用的类的都是由他来来加载实现的,也就是我们经常用到的classpath路径

package classLoader;

public class ClassLoader_test {
	public static void main(String[] args) {
		System.out.println(ClassLoader.getSystemClassLoader());
	}

}
sun.misc.Launcher$AppClassLoader@4e25154f

通过getparent()来获取相对应的父级

package classLoader;

public class ClassLoader_test {
	public static void main(String[] args) {
		System.out.println(ClassLoader.getSystemClassLoader());
		//AppClassLoader的父类应该是ExtClassLoader
		System.out.println(ClassLoader.getSystemClassLoader().getParent());
		//而ExtClassLoader的父类应该是bootstrap classloader,但是它是由C++实现的,那么java中是获取不到的
		System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
	}

}
sun.misc.Launcher$AppClassLoader@4e25154f
sun.misc.Launcher$ExtClassLoader@33909752
null

四、加载机制

代理模式

  交给其他加载器来加载指定的类

双亲委托机制

 就是给某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次追溯,直到最高的爷爷辈的,如果父类加载器可以完成类加载额任务,就成功返回;只有父类加载器无法完成的此加载任务时,自己才去加载

双亲委托机制是为了保证java核心库的类型安全

 这种机制就保证不会出现用户自己能定义java.lang.Object类的情况

类加载器处理用于加载类,也是安全的最基本的保障

双亲委托机制是代理模式的一种

 并不是所有的类加载器都采用双亲委托机制

 tomcat服务器的类加载器也是采用代理模式,所不同的它首先尝试去加载某个类,如果找不到再代理给父类加载器,这与一般类加载器的顺序是相反的。

 

举个栗子

 

比如我突然naocan,定义了一个java.lang.String的类,那么首先是从自定义类加载器开始,先传递给AppClassLoader,然后在传递给ExtClassLoader,最后传递给BootStrapclassLoader(加载核心包的),发现存在java.lang.String,那么就会加载String类,那么就会直接返回class。这样就保证了对于外部的包进行了安全性的保障

五、 java.lang.classLoader

作用:

 java.lang.classLoader的类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义java类,即java.lang.Class类的一个实例

 除此之外,ClassLoader还负责加载java应用所需的资源,如图像文件和配置文件

相关方法:

 getParent()  返回该类加载器的父类加载器

loadClass(String name) 加载名称为name的类,返回的结果是java.lang.class类的实例

Findclass(String name) 查找名称为name的类,返回的结果是java.lang.class的类的实例

defineClass(String name,byte[] b,int off,int lent) 把字节数组b中的 内容转化为java类,返回的是

Java.lang.class的类的实例,这个方法被声明为final的

resolveClass(Class<?> c)链接被指定的java类

对于以上给出的方法,表示类的名称的name参数的值是类的二进制名称,需要注意的是内部类的表示,如com.example.Sample$1和com.example.Sample$inner等表示方式

六、自定义加载器

package classLoader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import javassist.ByteArrayClassPath;

public class FileSystemClassLoader extends ClassLoader {
	private String rootDir;
	//定义了文件所在的根目录
	public  FileSystemClassLoader(String root)
	{
		this.rootDir=root;
	}
	@Override
    protected Class<?> findClass(String  name)throws ClassNotFoundException
    {
    	Class<?> class1=findLoadedClass(name);
    	//如果已经被加载了
    	if(class1!=null)
    	{
    		return class1;
    		
    	}
    	else 
    	{
    		
    	ClassLoader parent=this.getParent();
    	//让父级进行加载,如果加载成功那么直接返回
    	try
    	{
    	class1=parent.loadClass(name);
    	}
    	catch(Exception exception)
    	{
    		exception.printStackTrace();        
    	}
    	if(class1!=null)
    		return class1;
    	else 
    	{
    		byte[] classData = null;
			try {
				classData = getClassData(name);
			} catch (IOException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
    		if(classData==null)
    			 throw new ClassNotFoundException();
    		else 
    		{System.out.println(name+""+classData.toString()+"     "+classData.length);
    			class1=defineClass(name, classData, 0,classData.length);	
    		}
    	}
    	}
    	
    	return class1;
    	
    }
    public byte[] getClassData(String classname) throws IOException
    { String path=rootDir+"/"+classname.replace('.', '/')+".class";
    System.out.println(path);
    InputStream is=new FileInputStream(path);
    ByteArrayOutputStream byteArrayOutputStream=null;
    byte[] bs=new byte[1024];
    int length=0;
    try
    {
    	byteArrayOutputStream= new ByteArrayOutputStream();
    while((length=is.read(bs))!=-1)
    	byteArrayOutputStream.write(bs,0,length);
    return byteArrayOutputStream.toByteArray();
    }
    catch (Exception e) {
		// TODO: handle exception
    	e.printStackTrace();
    	System.out.println("wo是你个");
    	return null;
    	
	}
    finally {
        byteArrayOutputStream.close();
    	 is.close();
	}
   
   

    	
    }

}
package classLoader;

public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException {
	FileSystemClassLoader FilesystemClassLoader=new FileSystemClassLoader("d:/myjava");
     Class<?> class1=	FilesystemClassLoader.loadClass("com.bjsxt.bean.HelloWorld");
	System.out.println(class1);
}
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值