类加载器和类加载过程,java加载类的三种方式

  类加载器和类加载过程,java加载类的三种方式

  一、类与类加载器

  类装入器:装入阶段的第一步是通过类的完全限定名将类的二进制字节流装入jvm。

  类装入器:任何类的唯一性都是由其本身和装入它的类装入器决定的。两个类是否相等的前提是由同一个类装入器装入。

  jvm中有两种类装入器:一种是Bootstrap类装入器,用C实现;另一个是所有其他用java实现的类装入器。

  从java程序的角度来看:

  1)启动类加载器:负责加载JAVA_HOME\lib目录或-Xbootclasspath参数指定的路径中的类。另外,文件名需要被虚拟机识别,不被jvm识别就不能加载。

  2)扩展类加载器:负责加载JAVA_HOME\lib\exit目录或java.exit.dirs系统变量指定的路径下的所有类库。

  3)应用类加载器(系统类加载器):是类加载器中getSystemClassloader()方法的返回值。负责加载用户类路径上指定的类库。如果应用程序中没有自定义的类加载器,这就是应用程序中的默认类加载器。

  免费在线视频教学:java视频教程

  二、双亲委派模型

  如何解决写爬虫IP受阻的问题?立即使用。

  除了顶级启动类装入器,所有其他类装入器都有自己的父类装入器。父子关系不是通过继承实现的,而是通过组合关系重用父类加载器。

  工作过程:类加载器收到类加载请求——将请求委托给父类加载器(直到顶层类加载器启动)——父类尝试加载,加载失败反馈给子类加载器——子类加载器尝试加载。

  父委托模型的好处:保证了java底层API的稳定性,避免了加载相同基本类名(对象)的自定义类造成java基本行为的混乱,导致多个不同类同名。

  双亲委派模型源码:

  该方法增加了同步锁来保证线程安全。首先,检查类是否已经被加载。如果还没有加载,调用父类加载器的loadClass()方法。如果父类装入器为空,则调用启动类装入器。

  如果父类加载失败,会抛出ClassNotFoundException,调用自己的findClass()方法进行加载。

  受保护阶层?loadClass(字符串名称,布尔解析)

  引发ClassNotFoundException

  {

  //同步锁

  synchronized(getClassLoadingLock(name)){

  //首先检查这个类是否已经加载。

  班级?c=findLoadedClass(name);

  if (c==null) {

  long t0=system . nano time();

  尝试{

  如果(家长!=null) {

  //如果父类不为空,则调用父类加载器的loadClass方法

  c=parent.loadClass(name,false);

  }否则{

  //如果没有父类,默认调用启动类加载器加载。

  c=findBootstrapClassOrNull(name);

  }

  } catch(ClassNotFoundException e){

  //如果父类加载器找不到该类,则抛出ClassNotFoundException

  }

  if (c==null) {

  //当父类加载器失败时,调用自己的findClass方法进行加载。

  long t1=system . nano time();

  c=find class(name);

  //记录

  sun . misc . perf counter . getparentdelegationtime()。添加时间(t1-t0);

  sun . misc . perf counter . getfindclasstime()。addElapsedTimeFrom(t1);

  sun . misc . perf counter . getfindclass()。increment();

  }

  }

  如果(解决){

  resolve class(c);

  }

  返回c;

  }

  }三、破坏双亲委派模型

  1.第一次破坏

  JDK1.2之后出现了父委托模型,而类加载器和抽象类java.lang.ClassLoader已经存在。

  因此,为了向前兼容,在JDK1.2之后,一个新的受保护的方法findClass被添加到ClassLoader中。用户在findClass方法中编写自己的类加载逻辑,而不是重写loadClass方法,以保证自定义的类加载符合父委托模型。

  2.第二次破坏

  模型本身是有缺陷的。父母委托可以保证每个类装入器的基础类的统一性,这在用户代码调用基础类时不适用,但是如果基础类回调用户代码。比如涉及SPI的场景,用来加载需要的SPI代码。

  SPI机制介绍参考其他文章。

  为了解决这个问题,引入了线程上下文类加载器。这个类加载器可以由java.lang.Thread类中的setContextClassLoader()方法设置。如果在创建线程时没有设置它,它将从父线程继承一个。如果全局没有,默认情况下它将是应用程序类加载器。使用这个加载器,父类加载器可以请求子类加载器加载。

  3.第三次破坏

  由于追求程序动态,比如热部署,热替换等。

  例如,模块化标准OSGi R4.2将母公司委托的树形结构改变为更复杂的网络结构。

  java文章教程推荐:java入门教程以上是对java加载器的详细了解。请多关注我们的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: