深入JVM——类加载器(二)

本文深入探讨Java程序的动态扩展机制,介绍通过Class.forName方法及类加载器的loadClass方法实现类的动态加载,并通过示例代码展示不同类加载器加载同一类时的区别。

转自 http://xtu-tja-163-com.iteye.com/blog/770449

     上篇文章主要分析了类加载器的种类以及加载规则。下面,将主要分析下与加载器有关的java程序动态扩展
      这篇文章只挑了类加载器的一个问题来分析,如果要想了解类加载器的一些常见问题以及自定义类加载要注意的一些细节,可以参考我的上篇文章:
    http://xtu-tja-163-com.iteye.com/blog/770401

     Java的连接模型允许用户运行时扩展应用程序,既可以通过当前虚拟机中预定义的加载器加载编译时已知的类或者接口,又允许用户自行定义类装载器,在运行时动态扩展用户的程序,这就是Java程序动态扩展(运行时加载类)。java动态扩展有两种方式:

     1.采用Class.forName方法。动态扩展Java程序最直接的方式就是使用Class的forName()方法,它有两中重载形式:
       1)Class.forName(String className)
       2)Class.forName(String className,boolean initialize
)
      它们之间的关系是:Class.forName(string className) == Class.forName(string className,true)initialize参数用来指定加载className对应的类时,是否还进行初始化。有些场景下,需要将initialize设置为true来强制加载,同时完成初始化,例如典型的就是利用DriverManager进行JDBC驱动程序类注册的问题,因为每一个JDBC驱动程序类的静态初始化方法都用DriverManager注册驱动程序,这样才能被应用程序使用,这就要求驱动程序类必须被初始化,而不单单被加载.

     2.采用类加载器的loadClass方法来动态扩展java应用程序。它的加载过程已经在上面分析过了,采用的是委托双亲加载机制。这里注意,它虽然也有个loadClass(String className,boolean resolve)方法,resolve是加载指定名称的类以后,是否进行连接的标志,但是如果resolve为false,也不能保证被装载的类没被连接(例如指定的类在这之前已经被装载过了)。还有,用loadClass加载的类一般不进行初始化。

      最后,建议使用Class.forName()方法,因为,它在加载指定的类时,一定都会对加载的类进行初始化,而初始化在一些操作中是非常重要的,如果JDBC驱动的初始化。注意:类的初始化不等于new一个对象,如果对类的初始化不熟悉,可以参考我以前的一篇文章
       http://xtu-tja-163-com.iteye.com/admin/blogs/769226
     
在类加载器中,比较容易弄错的一个问题就是:由不同的类加载器加载的指定类型还是相同的类型吗?

    答案: 在Java中,一个类用其完全匹配类名(fully qualified class name)作为标识,这里指的完全匹配类名包括包名和类名。但在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识,不同类加载器加载的类将被置于不同的命名空间.我们可以用两个自定义类加载器去加载某自定义类型(注意,不要将自定义类型的字节码放置到系统路径或者扩展路径中,否则会被系统类加载器或扩展类加载器抢先加载),然后用获取到的两个Class实例进行java.lang.Object.equals(…)判断,将会得到不相等的结果。
   首先,在eclipse中部署好下面代码块:
  

Java代码   收藏代码
  1. package com.newTest.test3;  
  2.   
  3. public class TestClass {  
  4.   
  5.     static {  
  6.         System.out.println("我被加载了,加载我的加载器是:"+TestClass.class.getClassLoader());  
  7.     }  
  8.     public void print() {  
  9.         System.out.println("我被加载了,加载我的加载器是:"+TestClass.class.getClassLoader());  
  10.     }  
  11. }  
  12.   
  13. /** 
  14.  * 自定义加载器工厂 
  15.  */  
  16. public class ClassLoaderFactory {  
  17.       
  18.     private static ClassLoaderFactory  instatnce = new ClassLoaderFactory();  
  19.       
  20.     static String s ;  
  21.     public static ClassLoaderFactory getInstance() {  
  22.         return instatnce;  
  23.     }  
  24.       
  25.     //根据制定的路径生成不同的加载器  
  26.     public  ClassLoader  getClassLoader(String path) {  
  27.           
  28.         File file = new File(path);  
  29.         if(file.exists()) {  
  30.             file.mkdirs();  
  31.         }  
  32.           
  33.         URL url = null;  
  34.         try {  
  35.             String urlPath = file.getCanonicalPath()+File.separator;  
  36.             /* 
  37.              * 路径前一定要有'/',不然不对,我也不知道原因,知道的说下,谢谢 
  38.              */  
  39.             urlPath = urlPath.charAt(1)=='/'?urlPath:'/'+urlPath;      
  40.             String reposity = new URL("file",null,file.getCanonicalPath()+File.separator).toString();  
  41.             URLStreamHandler handler = null;  
  42.             url = new URL(null,reposity,handler);  
  43.         } catch (Exception e) {  
  44.             e.printStackTrace();  
  45.             //记录日志 抛出异常  
  46.         }   
  47.            //生成类加载器,记住:如果你要调试,一定要把它的父加载器设置为null  
  48.         return new URLClassLoader(new URL[]{url},null);  
  49.     }  
  50.   
  51.     @SuppressWarnings({ "unchecked" })  
  52.     public static void main(String[] args) throws Exception {  
  53.           
  54.         String path1 = "D:/classReposity";  
  55.         String path2 =  "D:/classReposityCopy";  
  56.           
  57.         //---------生成两个自定义类加载器--------------------  
  58.         ClassLoader loader1 = ClassLoaderFactory.getInstance().getClassLoader(path1);  
  59.         ClassLoader loader2 = ClassLoaderFactory.getInstance().getClassLoader(path2);  
  60.           
  61.         //-----------------采用同一个加载器加载同一个类型实例------------  
  62.         Class c = loader1.loadClass("com.newTest.test3.TestClass");  
  63.         Class c2 = loader1.loadClass("com.newTest.test3.TestClass");  
  64.           
  65.         //-----------------采用另外一个加载器加载同一个类型实例----------------  
  66.         //注意,采用loadClass加载的类时,可能不会被初始化,也就是说,暂时还不会执行TestClass中静态块内容  
  67.         Class c3 = loader2.loadClass("com.newTest.test3.TestClass");  
  68.           
  69.         System.out.println("使用同一个类加载器加载的类实例,是否相等?结果是:"+c.equals(c2));  
  70.         System.out.println("使用不同的类加载器加载的类实例,是否相等?结果是:"+c.equals(c3));  
  71.           
  72.         //执行加载出的c的一个实例的print方法  
  73.         c.getMethod("print"new Class[]{}).invoke(c.newInstance(), new Object[]{});  
  74.   
  75.     }  
  76.       
  77. }  
    

   经过编译后,把生成的Test.class文件分别放在path1和path2目录下,注意:如 果有包,要放在path1或path2的包目录下,如:path1/com/netTest/test3/下
   最后,执行上面程序,得出如下结果:
   
使用同一个类加载器加载的类实例,是否相等?结果是:true
使用不同的类加载器加载的类实例,是否相等?结果是:false
我被加载了,加载我的加载器是:java.net.URLClassLoader@c17164
我被加载了,加载我的加载器是:java.net.URLClassLoader@c17164

基于径向基函数神经网络RBFNN的自适应滑模控制学习(Matlab代码实现)内容概要:本文介绍了基于径向基函数神经网络(RBFNN)的自适应滑模控制方法,并提供了相应的Matlab代码实现。该方法结合了RBF神经网络的非线性逼近能力和滑模控制的强鲁棒性,用于解决复杂系统的控制问题,尤其适用于存在不确定性和外部干扰的动态系统。文中详细阐述了控制算法的设计思路、RBFNN的结构与权重更新机制、滑模面的构建以及自适应律的推导过程,并通过Matlab仿真验证了所提方法的有效性和稳定性。此外,文档还列举了大量相关的科研方向和技术应用,涵盖智能优化算法、机器学习、电力系统、路径规划等多个领域,展示了该技术的广泛应用前景。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的研究生、科研人员及工程技术人员,特别是从事智能控制、非线性系统控制及相关领域的研究人员; 使用场景及目标:①学习和掌握RBF神经网络与滑模控制相结合的自适应控制策略设计方法;②应用于电机控制、机器人轨迹跟踪、电力电子系统等存在模型不确定性或外界扰动的实际控制系统中,提升控制精度与鲁棒性; 阅读建议:建议读者结合提供的Matlab代码进行仿真实践,深入理解算法实现细节,同时可参考文中提及的相关技术方向拓展研究思路,注重理论分析与仿真验证相结合。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值