繁体   English   中英

引用类的Java类加载机制

[英]Java Class loading mechanism for referenced Classes

加载类A ,假定A的字节码具有对许多其他类的引用。 假设A类如下所示。

class A extends B implements C,D {

    static E e;

    F f;

    A() {

      G g = new G();

    }

    void print(H h) {

    }
}

JVM是否加载A使用的所有类? 还是在类初始化之前就不用理会它们?

如果至少其中一些已加载,是否在A完成后加载它们? A's加载将暂停直到所需的类加载?

对于此问题,假定尚未加载其他任何类。 甚至是超一流的B类和CD接口。

要了解这一点,让我们了解一些基本知识。 这将帮助任何新手了解JAVA中的延迟加载。

如果您熟悉Netscape的Web浏览器并且同时使用了3.x和4.x版本,那么无疑会发现Java运行时的加载方式有所不同。 如果您在Netscape 3启动时查看启动画面,您会注意到它会加载各种资源,包括Java。 但是,当您启动Netscape 4.x时,它不会加载Java运行时-它会等到您访问包含该标记的Web页面。 这两种方法说明了急切的实例化(需要时将其加载)和延迟实例化(等待直到被请求之前再加载它,因为它可能永远不需要)的技术。

这两种方法都有缺点:一方面,如果在该会话期间未使用资源,则始终加载资源可能会浪费宝贵的内存;另一方面,如果资源在该会话期间未使用,则可能会浪费宝贵的内存。 另一方面,如果尚未加载,则需要在首次需要资源时以加载时间为代价。

将惰性实例化视为资源保护策略

Java中的延迟实例化分为两类:

  • 延迟类加载
  • 项目清单

延迟类加载

Java运行时具有内置的类的惰性实例化。 类仅在首次引用时才加载到内存中。 (它们也可以首先通过HTTP从Web服务器加载。)

 MyUtils.classMethod();   //first call to a static class method
 Vector v = new Vector(); //first call to operator new

延迟类加载是Java运行时环境的重要功能,因为它可以在某些情况下减少内存使用。 例如,如果在会话期间从不执行程序的一部分,则永远不会加载仅在程序的该部分中引用的类。

惰性对象创建

延迟对象的创建与延迟类的加载紧密相关。 第一次在以前尚未加载的类类型上使用new关键字时,Java运行时将为您加载它。 与惰性类加载相比,惰性对象的创建可以减少更多的内存使用。

为了介绍惰性对象创建的概念,让我们看一个简单的代码示例,其中框架使用MessageBox来显示错误消息:

   public class MyFrame extends Frame
  {
  private MessageBox mb_ = new MessageBox();
  //private helper used by this class
  private void showMessage(String message)
  {
    //set the message text
    mb_.setMessage( message );
    mb_.pack();
    mb_.show();
  }
}

在上面的示例中,当创建MyFrame的实例时,还将创建MessageBox实例mb_。 相同的规则递归适用。 因此,在类MessageBox的构造函数中初始化或分配的所有实例变量也将在堆外分配,依此类推。 如果MyFrame实例不用于在会话中显示错误消息,则我们不必要地浪费了内存。

在这个相当简单的示例中,我们并不会真正获得太多收益。 但是,如果考虑一个更复杂的类,该类使用许多其他类,这些类又依次递归使用和实例化更多对象,则潜在的内存使用情况会更加明显。

  public final class MyFrame extends Frame
  {
  private MessageBox mb_ ; //null, implicit
  //private helper used by this class
  private void showMessage(String message)
  {
    if(mb_==null)//first call to this method
      mb_=new MessageBox();
    //set the message text
    mb_.setMessage( message );
    mb_.pack();
    mb_.show();
  }
}

如果仔细看showMessage(),您会发现我们首先确定实例变量mb_是否等于null。 由于尚未在声明时初始化mb_,因此Java运行时已为我们完成了此工作。 因此,我们可以安全地通过创建MessageBox实例进行操作。 以后所有对showMessage()的调用都会发现mb_不等于null,因此跳过了对象的创建并使用了现有实例。

结论 :一旦有子实体初始化,它将加载所有依赖对象。为了减少内存占用,我们应该在虚拟代理,延迟初始化等设计模式上谨慎寻找这些依赖对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM