引用类的Java类加载机制

问题描述 投票:0回答:1

当加载类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 class jvm lazy-loading classloader
1个回答
1
投票

要理解这一点,请了解一些基础知识。这将有助于任何新手了解JAVA中的延迟加载。

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

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

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

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运行时将为您加载它。与延迟类加载相比,延迟对象创建可以更大程度地减少内存使用。

为了介绍惰性对象创建的概念,让我们看一个简单的代码示例,其中Frame使用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,因此跳过对象的创建并使用现有实例。

结论:一旦用子实体初始化它就会加载所有依赖对象。为了减少内存占用,我们应该仔细查看设计模式上的这类,如虚拟代理,延迟初始化

© www.soinside.com 2019 - 2024. All rights reserved.