欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

Java基础-知识点总结-Java类加载器,java-java

来源: javaer 分享于  点击 29476 次 点评:139

Java基础-知识点总结-Java类加载器,java-java


Java类加载器

 

      类加载器(classloader)用来加载 Java 类到 Java虚拟机中。一般来说,Java虚拟机使用 Java类的方式如下:Java源程序(.java文件)在经过 Java编译器编译之后就被转换成 Java字节代码(.class文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。

 

 

 

演示类加载器的树状组织结构

 

public class ClassLoaderTree { 
    public static void main(String[] args) { 
    	//获取加载该类的类加载器
        ClassLoader loader = ClassLoaderTree.class.getClassLoader(); 
        while (loader != null) { 
            System.out.println(loader.toString());
            //获取该类加载器的父加载器
            loader = loader.getParent(); 
        } 
    } 
 }

 

 

 

 

 

 

 

 

      打印结果为:

 

      sun.misc.Launcher$AppClassLoader@addbf1

 

sun.misc.Launcher$ExtClassLoader@42e816

 

类加载器的委托机制

 

  • 每个类加载器加载类时,又先委托给其上级类加载器。

  •  

    方法

    说明

    getParent()

    返回该类加载器的父类加载器。

    loadClass(String name)

    加载名称为name的类,返回的结果是java.lang.Class类的实例。

    findClass(String name)

    查找名称为name的类,返回的结果是java.lang.Class类的实例。

    findLoadedClass(String name)

    查找名称为name的已经被加载过的类,返回的结果是java.lang.Class类的实例。

    defineClass(String name, byte[] b, int off, int len)

    把字节数组b中的内容转换成 Java类,返回的结果是 java.lang.Class类的实例。这个方法被声明为final的。

    resolveClass(Class<?> c)

    链接指定的 Java类。

     

    【编写自己的类加载器】

     

    创建自定义加载器类

     

    package cn.itcast.day2;
    
    import java.io.ByteArrayOutputStream;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    
    //自定义加载器类必须继承ClassLoader
    public class MyClassLoader extends ClassLoader{
    	//定义变量存储要加载的.Class文件所在目录
    	private String classDir;
    	
    	//构造方法
    	public MyClassLoader(){
    		
    	}
    	public MyClassLoader(String classDir){
    		this.classDir = classDir;
    	}
    	
    	//主函数用于将指定.calss文件加密并存放到指定位置
    	public static void main(String[] args) {
    		//获取要加密的源
    		String srcPath = args[0];
    		//获取加密后文件存放的路径
    		String destDir = args[1];
    		//设置目的
    		String destPath = destDir + "\\"+ srcPath.substring(srcPath.lastIndexOf('\\')+1);
    		
    		//创建输入流和输出流对象
    		FileInputStream fis = null;
    		FileOutputStream fos = null;
    		
    		try{
    			fis = new FileInputStream(srcPath);
    			fos = new FileOutputStream(destPath);
    			//调用加密方法
    			cepher(fis,fos);
    		}catch(IOException e){
    			throw new RuntimeException();
    		}finally{
    			try{
    				if(fos != null)
    					fos.close();
    			}catch(IOException e){
    				e.printStackTrace();
    			}
    			try{
    				if(fis != null)
    					fis.close();
    			}catch(IOException e){
    				e.printStackTrace();
    			}
    		}
    
    	}
    	
    	//定义加密解密方法
    	public static void cepher(InputStream ips,OutputStream ops){
    		int b = -1;
    		try{
    			while((b = ips.read())!= -1){
    				ops.write(b ^ 0xff);
    			}
    		}catch(IOException e){
    			throw new RuntimeException("加密失败!");
    		}finally{
    			try{
    				if(ops != null)
    					ops.close();
    			}catch(IOException e){
    				e.printStackTrace();
    			}
    			try{
    				if(ips != null)
    					ips.close();
    			}catch(IOException e){
    				e.printStackTrace();
    			}
    		}
    	}
    	
    	@Override
    	//覆盖findClass方法,只让本加载器加载
    	protected Class<?> findClass(String arg0) throws ClassNotFoundException {
    		System.out.println(arg0);
    		
    		//获取指定位置的.class文件
    		String classFileName = classDir + "\\" + arg0.substring(arg0.lastIndexOf('.')+1) + ".class";
    		
    		//创建输入流,字符数组输出流
    		FileInputStream fis = null;
    		ByteArrayOutputStream bos = null;
    		
    		//将.class文件进行解密,并返回解密后的.class文件
    		try{
    			fis = new FileInputStream(classFileName);
    			bos = new ByteArrayOutputStream();
    			//解密
    			cepher(fis,bos);
    			byte[] bytes = bos.toByteArray();
    			//defineClass()方法将字符数组转换为.class文件
    			return defineClass(bytes, 0, bytes.length);
    			
    		}catch(IOException e){
    			throw new RuntimeException();
    		}finally{
    			try{
    				if(bos != null)
    					bos.close();
    			}catch(IOException e){
    				e.printStackTrace();
    			}
    			try{
    				if(fis != null)
    					fis.close();
    			}catch(IOException e){
    				e.printStackTrace();
    			}
    		}
    	}
    }
    

    创建类,并用MyClassLoader进行加密

     

    package cn.itcast.day2;
    
    import java.util.Date;
    
    public class ClassLoaderAtt extends Date {
    	public String toString(){
    		return "hello java";
    	}
    }

     

     

     

     

     

     

     

     

    运行MyClassLoader参数为E:\test\javaenhance\bin\cn\itcast\day2\ClassLoaderAtt.class

     

    itcastlib(该目录是相对路径)

     

    运行完程序,会在itcastlib目录中生成加密的ClassLoaderAttachment.class,然后删除E:\test\javaenhance\bin\cn\itcast\day2目录中的ClassLoaderAttachment.class,因为不删除的话自定义加载器的loadClass方法会把此目录下的ClassLoaderAttachment.class加载,而不是调用findClass方法查找被自定义加载器加密的ClassLoaderAttachment.class

     

    测试类

     

    package cn.itcast.day2;
    import java.util.Date;
    public class ClassLoaderTest {
    	public static void main(String[] args) {
    		try {
    			//用自定义加载器加载.class文件
    			Class clazz = new MyClassLoader("itcastlib").loadClass("cn.itcast.day2.ClassLoaderAtt");
    			//实例化对象
    			Date d = (Date)clazz.newInstance();
    			System.out.println(d);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    }

     

     

     

     

    相关文章

      暂无相关文章
    相关栏目:

    用户点评