黑马程序员_JAVA_类加载器

本文深入探讨Java类加载器的工作原理,包括系统默认的三种主要类加载器:BootStrap、ExtClassLoader和AppClassLoader。文章详细解释了类加载器之间的父子关系及委托机制,并通过示例介绍了如何编写自定义类加载器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

------- android培训java培训、期待与您交流! ----------

类加载器:用来加载类的工具。

Java虚拟机中可以安装多个类加载器,

系统默认三个主要类加载器,每个类负责加载特定位置的类:

BootStrap,
ExtClassLoader,AppClassLoader

类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,既然这样第一个类加载器又是谁加载的呢?

显然必须有第一个类加载器不是不是java类,这正是BootStrap。

Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。
 体验类加载器

public class ClassLoaderTest 
{

		public static void main(String[] args) throws Exception 
		{
	
			System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
		
		} 
}



       用eclipse的打包工具将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包,再在eclipse中运行这个类,运行结果显示为ExtClassLoadr。此时的环境状态是classpath目录有ClassLoaderTest.class,ext/itcast.jar包中也有ClassLoaderTest.class,这时候我们就需要了解类加载的具体过程和原理了。

类加载的之间的父子关系和管辖范围
      优先由父类加载,如上面所说的,存在了两份.class文件,则按照父类先加载的原则,由ExtClassLoader进行加载
extClassLoader类加载器专门是加载图上指定目录的.jar文件,只要放文件到该目录,都有该加载器加载。  
 

类加载器的委托机制
     当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
     1   首先当前线程的类加载器去加载线程中的第一个类。
     2   如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。 
     3   还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

每个类加载器加载类时,又先委托给其上级类加载器。
      1当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?
     2每个ClassLoader本身只能分别加载特定位置和目录中的类,但它们可以委托其他的类装载器去加载类,这就是类加载器的委托模式。类装载器一级级委托到BootStrap类加载器,当BootStrap无法加载当前所要加载的类时,然后才一级级回退到子孙类装载器去进行真正的加载。当回退到最初的类装载器时,如果它自己也不能完成类的装载,那就应报告ClassNotFoundException异常。

问:能不能自己写个类叫java.lang.System?
答:为了不让我们写System类,类加载采用委托机制,这样可以保证爸爸们优先,也就是总是使用爸爸们能找到的类,
这样总是使用java系统提供的System。

把先前编写的类加入到jdk的rt.jar中,会有怎样的效果呢?不行!!!
看来是不能随意将自己的class文件加入进rt.jar文件中的。

编写自己的类加载器,加载特定目录中的类,其他加载器不可以加载

编写自己的类加载器

1. 知识讲解

自定义义的类加载器必须继承ClassLoader

loadClass方法与findClass方法

defineClass方法

2. 编程步骤

1. 编写一个对文件内容进行简单加密的程序

2. 编写一个自己的类装载器,可以实现对加密过的类装载和界面

3. 编写一个程序调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类,程序中可以除了使用ClassLoader.load方法之外,还可以使用设置线程的上下文类加载器或者系统加载器,然后使用Class.forName

3. 实验步奏

1. 对不带包名的class文件进行加密,加密结果存放到另外一个目录,例如:javaMyClassLoader MyTest.classs  F:\itcast

2. 运行加载类的程序,结果能够被正常加载,但打印出来的类装载器名称为AppC

lassLaoder: javaMyClassLoader MyTest F:\itcast

3. 用加密后的类文件替换CLASSPATH环境下的类文件,再执行上一步操作就出现问题了,错误说明是AppClassLoader类装载失败

4. 删除CLASSSPATH环境下的类文件,再执行上一步操作就没有问题了

 

 

 

编写对class文件进行加密的工具类

package com.itcast.day2;

 

import java.io.*;

 

public class MyClassLoader

{

   public staticvoid main(String[] args) throws Exception

         {

           

                   StringsrcPath=args[0];

                   StringdestDir=args[1];

                   StringdestName=srcPath.substring(srcPath.lastIndexOf("\\")+1);//分割得到文件名

                   StringdestPath=destDir+"\\"+destName;//拼装路径

                   FileInputStreamfis=new FileInputStream(srcPath);

                   FileOutputStreamfos=new FileOutputStream(destPath);

                   cyhelper(fis,fos);

                   fis.close();

                   fos.close();

                   //G:\Programme\Myeclipse_set\workspace_eclipse\hibernate\java_enhance\bin\ClassLoaderAttachment.class

         }
 //简单加密算法

   private staticvoid cyhelper(InputStreamips,OutputStream ops) throwsException

   {

            intb=-1;

            while((b=ips.read())!=-1)

            {

                      ops.write(b^0xff);

            }

   }

}

import java.util.Date;

 

public class ClassLoaderAttachmentextends Date

{

   @Override

         public String toString()

         {

                   return "helloitcast";

         }

}

 



  

  

 


将生成的itcastlib目录下的ClassLoaderAttachment.class 替换掉原来的class文件

package com.itcast.day2;

 

public class ClassLoaderTest

{

    public staticvoid main(String[] args)

         {

            

            //打印出hello itcast

            System.out.println(new ClassLoaderAttachment().toString());

         }

}


 

编写和测试自己编写的解密类加载器

package com.itcast.day2;

import java.util.Date;

 

public class ClassLoaderAttachmentextends Date

{

   @Override

         public String toString()

         {

                   return "helloitcast";

         }

}

 

 

package com.itcast.day2;

 

import java.io.*;

 

public class MyClassLoader extends ClassLoader

{

   public staticvoid main(String[] args) throws Exception

         {

           

                   StringsrcPath=args[0];

                   StringdestDir=args[1];

                   StringdestName=srcPath.substring(srcPath.lastIndexOf("\\")+1);

                   StringdestPath=destDir+"\\"+destName;//拼装路径

                   FileInputStreamfis=new FileInputStream(srcPath);

                   FileOutputStreamfos=new FileOutputStream(destPath);

                   cyhelper(fis,fos);

                   fis.close();

                   fos.close();

                   //G:\Programme\Myeclipse_set\workspace_eclipse\hibernate\java_enhance\bin\ClassLoaderAttachment.class

         }

  

   //简单加密算法

   private staticvoid cyhelper(InputStreamips,OutputStream ops) throwsException

   {

            intb=-1;

            while((b=ips.read())!=-1)

            {

                      ops.write(b^0xff);//0->1  1->0

            }

   }

    private String classDir;

   //覆盖方法

   @Override

         protected Class<?> findClass(String name) throws ClassNotFoundException

         {

            String classFileName=classDir+"\\"+name+".class";//找文件

            FileInputStream fis=null;

            try

                   {

                      fis=newFileInputStream(classFileName);

                      ByteArrayOutputStream bos=new ByteArrayOutputStream();//转成字节数组,方便操作

                      cyhelper(fis,bos);//解密

                      fis.close();

                      byte[]bytes=bos.toByteArray();

                      return defineClass(bytes,0,bytes.length);

                   }

             catch(Exception e)

                   {

                      System.out.println("出现异常");

                            e.printStackTrace();

                   }

          

            return super.findClass(name);

         }

    public MyClassLoader()

         {

        

         }

    public MyClassLoader(String classDir)

     {

               this.classDir=classDir;

     }

   

}


     运行之前,先删除掉原来的 ClassLoaderAttachment .class文件,这样安装流程走会运行MyClassLoader类的loadClass()方法,其父类的加载器会先运行,但是找不到原先的ClassLoaderAttachment.class文件,这时就运行findClass()方法,该方法我们已经覆盖了,所以会去找指定目录的.class文件,也就是在itcastlib中的加密的.class文件。

如果没有删除掉原先的.class文件的话,那父类加载器就会加载,而不是用到自定义的加载器了。

package com.itcast.day2;

 

import java.util.Date;

 

public class ClassLoaderTest

{

    public staticvoid main(String[] args) throws Exception

    {

            //打印出hello itcast

          //  System.out.println(new ClassLoaderAttachment().toString());

           Class classzz=new MyClassLoader("itcastlib").loadClass("ClassLoaderAttachment");

           Date d1=(Date) classzz.newInstance();

           System.out.println(d1);

         }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值