模块 java.base
 java.lang

类 ModuleLayer

java.lang.Object
java.lang.ModuleLayer

public final class ModuleLayer extends Object
Java 虚拟机中的一层模块。

层是根据 Configuration 中的模块图和将每个模块映射到 ClassLoader 的函数创建的。创建一个层通知 Java 虚拟机关于可以从模块加载的类,以便 Java 虚拟机知道每个类是哪个模块的成员。

创建层会为配置中的每个 ResolvedModule 创建一个 Module 对象。对于每个已解析的模块,即 read Module reads 对应的运行时 Module,它们可能位于同一层或 parent 层。

defineModulesWithOneLoader defineModulesWithManyLoaders 方法提供了创建模块层的便利方法,其中所有模块都映射到单个类加载器,或者每个模块都映射到自己的类加载器。 defineModules 方法适用于更高级的情况,其中模块通过指定给该方法的函数映射到自定义类加载器。这些方法中的每一个都有一个实例和静态变体。实例方法创建一个以接收器为父层的层。静态方法适用于更高级的情况,其中可以有多个父层或需要 Controller 来控制层中的模块

一个Java虚拟机至少有一个非空层,即boot 层,它是在Java虚拟机启动时创建的。引导层包含模块 java.base,并且是 Java 虚拟机中唯一具有名为“java.base”的模块的层。引导层中的模块被映射到 Java 虚拟机中的引导类加载器和其他类加载器。创建附加层时,引导层通常是parent

创建层中的每个Module,以便它exports opens 由其ModuleDescriptor 描述的包。合格的导出(包导出到一组目标模块而不是所有模块)在创建层时具体化如下:

  • 如果模块 X 将包导出到 Y,并且如果运行时 Module X 读取 Module Y,则包将导出到 Module Y(可能与 X 在同一层或父层)。
  • 如果模块 X 将包导出到 Y,并且如果运行时 Module X 不读取 Y,则目标 Y 就像调用 findModule 在层或其父层中查找模块一样定位。如果找到 Y,则将包导出到找到的 Y 实例。如果未找到 Y,则忽略合格的导出。

合格的打开与合格的输出以相同的方式处理。

与创建 Configuration 一样,automatic 模块在创建层时会受到特殊对待。在 Java 虚拟机中创建一个自动模块作为Module,它读取 Java 虚拟机中每个未命名的 Module

除非另有说明,否则将 null 参数传递给此类中的方法会导致抛出 NullPointerException

示例

此示例通过将引导层的配置作为父级解析名为“myapp”的模块来创建配置。然后它使用此配置中的模块创建一个新层。所有模块都定义到同一个类加载器。

  ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
  ModuleLayer parent = ModuleLayer.boot();
  Configuration cf = parent.configuration()
               .resolve(finder, ModuleFinder.of(), Set.of("myapp"));
  ClassLoader scl = ClassLoader.getSystemClassLoader();
  ModuleLayer layer = parent.defineModulesWithOneLoader(cf, scl);
  Class<?> c = layer.findLoader("myapp").loadClass("app.Main");
 
自从:
9
参见:
  • 方法详情

    • defineModulesWithOneLoader

      public ModuleLayer  defineModulesWithOneLoader(Configuration  cf, ClassLoader  parentLoader)
      通过将给定 Configuration 中的模块定义到 Java 虚拟机,创建一个新的模块层,并将该层作为其父层。此方法创建一个类加载器并为该类加载器定义所有模块。每个类加载器的parent 是给定的父类加载器。当以该层作为父层调用时,此方法的工作方式与静态 defineModulesWithOneLoader 方法的指定完全相同。换句话说,如果这一层是thisLayer那么这个方法相当于调用:
       
         ModuleLayer.defineModulesWithOneLoader(cf, List.of(thisLayer), parentLoader).layer();
        
      参数:
      cf - 层的配置
      parentLoader - 该方法创建的类加载器的父类加载器;对于引导类加载器,可能是 null
      返回:
      新创建的图层
      抛出:
      IllegalArgumentException - 如果给定的配置有多个父级或配置的父级不是这一层的配置
      LayerInstantiationException - 如果由于静态 defineModulesWithOneLoader 方法指定的任何原因无法创建图层
      SecurityException - 如果 RuntimePermission("createClassLoader")RuntimePermission("getClassLoader") 被安全管理器拒绝
      参见:
    • defineModulesWithManyLoaders

      public ModuleLayer  defineModulesWithManyLoaders(Configuration  cf, ClassLoader  parentLoader)
      通过将给定 Configuration 中的模块定义到 Java 虚拟机,创建一个新的模块层,并将该层作为其父层。每个模块都定义为其自己的 ClassLoader ,由此方法创建。每个类加载器的parent 是给定的父类加载器。当以该层作为父层调用时,此方法的工作方式与静态 defineModulesWithManyLoaders 方法的指定完全相同。换句话说,如果这一层是thisLayer那么这个方法相当于调用:
       
         ModuleLayer.defineModulesWithManyLoaders(cf, List.of(thisLayer), parentLoader).layer();
        
      参数:
      cf - 层的配置
      parentLoader - 此方法创建的每个类加载器的父类加载器;对于引导类加载器,可能是 null
      返回:
      新创建的图层
      抛出:
      IllegalArgumentException - 如果给定的配置有多个父级或配置的父级不是这一层的配置
      LayerInstantiationException - 如果由于静态 defineModulesWithManyLoaders 方法指定的任何原因无法创建层
      SecurityException - 如果 RuntimePermission("createClassLoader")RuntimePermission("getClassLoader") 被安全管理器拒绝
      参见:
    • defineModules

      public ModuleLayer  defineModules(Configuration  cf, Function <String ,ClassLoader > clf)
      通过将给定 Configuration 中的模块定义到 Java 虚拟机,创建一个新的模块层,并将该层作为其父层。每个模块都通过给定的函数按名称映射到它的类加载器。当以该层作为父层调用时,此方法的工作方式与静态 defineModules 方法所指定的完全相同。换句话说,如果这一层是thisLayer那么这个方法相当于调用:
       
         ModuleLayer.defineModules(cf, List.of(thisLayer), clf).layer();
        
      参数:
      cf - 层的配置
      clf - 将模块名称映射到类加载器的函数
      返回:
      新创建的图层
      抛出:
      IllegalArgumentException - 如果给定的配置有多个父级或配置的父级不是这一层的配置
      LayerInstantiationException - 如果由于静态 defineModules 方法指定的任何原因无法创建层
      SecurityException - 如果 RuntimePermission("getClassLoader") 被安全管理器拒绝
    • defineModulesWithOneLoader

      public static ModuleLayer.Controller  defineModulesWithOneLoader(Configuration  cf, List <ModuleLayer > parentLayers, ClassLoader  parentLoader)
      通过将给定 Configuration 中的模块定义到 Java 虚拟机来创建一个新的模块层。此方法创建一个类加载器并为该类加载器定义所有模块。

      通过此方法创建的类加载器在从模块加载类时实现了direct delegation。如果调用 loadClass 方法来加载类,则它使用类的包名称将其映射到模块。这可能是这一层中的一个模块,因此定义到同一个类加载器。它可以是父层中模块中的包,导出到该层中的一个或多个模块。类加载器委托给模块的类加载器,如果该类加载器未找到则抛出 ClassNotFoundException。当调用 loadClass 来加载未映射到模块的类时,它会委托给父类加载器。

      该方法创建的类加载器在查找父类加载器之前,先定位层内所有模块中的资源(getResource getResources 等资源方法)。

      尝试创建一个所有模块都定义为同一个类加载器的层可能会失败,原因如下:

      • Overlapping packages:配置中的两个或多个模块具有相同的包。

      • Split delegation:生成的类加载器需要委托给多个类加载器才能加载特定包中的类。

      此外,如果配置包含名为“java.base”的模块,或者模块包含名为“java”的包或名称以“java.”开头的包,则无法创建层。

      如果存在安全管理器,则由此方法创建的类加载器将加载具有受此方法调用上下文限制的权限的类和资源。

      参数:
      cf - 层的配置
      parentLayers - 按搜索顺序排列的父层列表
      parentLoader - 该方法创建的类加载器的父类加载器;对于引导类加载器,可能是 null
      返回:
      控制新创建层的控制器
      抛出:
      IllegalArgumentException - 如果给定配置的父层与父层的配置不匹配,包括顺序
      LayerInstantiationException - 如果由于上述任何原因无法将所有模块定义到同一个类加载器
      SecurityException - 如果 RuntimePermission("createClassLoader")RuntimePermission("getClassLoader") 被安全管理器拒绝
      参见:
    • defineModulesWithManyLoaders

      public static ModuleLayer.Controller  defineModulesWithManyLoaders(Configuration  cf, List <ModuleLayer > parentLayers, ClassLoader  parentLoader)
      通过将给定 Configuration 中的模块定义到 Java 虚拟机来创建一个新的模块层。每个模块都定义为其自己的 ClassLoader ,由此方法创建。每个类加载器的parent 是给定的父类加载器。

      通过此方法创建的类加载器在从模块加载类时实现 direct delegation。如果调用 loadClass 方法来加载类,则它使用类的包名称将其映射到模块。包可能在为类加载器定义的模块中。该包可以由该层中的另一个模块导出到定义给类加载器的模块。它可能位于父层中的模块导出的包中。类加载器委托给模块的类加载器,如果该类加载器未找到则抛出 ClassNotFoundException。当调用 loadClass 来加载未映射到模块的类时,它会委托给父类加载器。

      通过此方法创建的类加载器在搜索父类加载器之前在定义给类加载器的模块中定位资源(getResource getResources 和其他资源方法)。

      如果有安全管理器,则由此方法创建的类加载器将加载具有受此方法的调用上下文限制的特权的类和资源。

      参数:
      cf - 层的配置
      parentLayers - 按搜索顺序排列的父层列表
      parentLoader - 此方法创建的每个类加载器的父类加载器;对于引导类加载器,可能是 null
      返回:
      控制新创建层的控制器
      抛出:
      IllegalArgumentException - 如果给定配置的父层与父层的配置不匹配,包括顺序
      LayerInstantiationException - 如果由于配置包含名为“java.base”的模块或模块包含名为“java”的包或名称以“java.”开头的包而无法创建层
      SecurityException - 如果 RuntimePermission("createClassLoader")RuntimePermission("getClassLoader") 被安全管理器拒绝
      参见:
    • defineModules

      public static ModuleLayer.Controller  defineModules(Configuration  cf, List <ModuleLayer > parentLayers, Function <String ,ClassLoader > clf)
      通过将给定 Configuration 中的模块定义到 Java 虚拟机来创建一个新的模块层。给定的函数按名称将配置中的每个模块映射到类加载器。创建该层会通知 Java 虚拟机有关可能加载的类,以便 Java 虚拟机知道每个类是哪个模块的成员。

      类加载器实现的类加载器委托必须尊重模块的可读性。类加载器应该是 parallel-capable 以避免在类加载期间出现死锁。此外,使用此方法创建新层的实体应安排类加载器在尝试加载类或资源之前准备好从这些模块加载。

      创建层可能会因以下原因而失败:

      • 具有相同包的两个或多个模块被映射到相同的类加载器。

      • 一个模块被映射到一个已经定义了同名模块的类加载器。

      • 一个模块被映射到一个类加载器,该类加载器已经在模块中的任何包中定义了类型。

      此外,如果配置包含名为“java.base”的模块,则无法创建层,配置包含带有名为“java”的包的模块或以“java.”开头的包名称,或将模块名称映射到的函数类加载器返回 null平台类加载器

      如果将模块名称映射到类加载器的函数抛出错误或运行时异常,则它会传播到此方法的调用者。

      API 注意:
      关于使用此方法创建层是否是原子操作,它是特定于实现的。因此,此方法可能会因某些模块(但不是全部)定义到 Java 虚拟机而失败。
      参数:
      cf - 层的配置
      parentLayers - 按搜索顺序排列的父层列表
      clf - 将模块名称映射到类加载器的函数
      返回:
      控制新创建层的控制器
      抛出:
      IllegalArgumentException - 如果给定配置的父层与父层的配置不匹配,包括顺序
      LayerInstantiationException - 如果由于上述任何原因导致图层创建失败
      SecurityException - 如果 RuntimePermission("getClassLoader") 被安全管理器拒绝
    • configuration

      public Configuration  configuration()
      返回该层的配置。
      返回:
      该层的配置
    • parents

      public List <ModuleLayer > parents()
      按搜索顺序返回该图层父级的不可修改列表。如果这是 空层,则返回一个空列表。
      返回:
      该层父级的可能为空的不可修改列表
    • modules

      public Set <Module > modules()
      返回该层中一组不可修改的模块。
      返回:
      该层中一组可能为空的不可修改的模块
    • findModule

      public Optional <Module > findModule(String  name)
      返回该层中具有给定名称的模块,如果不在该层中,则返回 parent 层。在父层中查找模块相当于按搜索顺序在每个父层上调用 findModule,直到找到模块或搜索到所有父层。在 tree of layers 中,这相当于深度优先搜索。
      参数:
      name - 要查找的模块的名称
      返回:
      具有给定名称的模块或一个空的 Optional 如果在该层或任何父层中没有具有该名称的模块
    • findLoader

      public ClassLoader  findLoader(String  name)
      返回具有给定名称的模块的 ClassLoader。如果给定名称的模块不在该层中,则以 findModule 指定的方式搜索 parent 层。

      如果有安全管理器,则使用 RuntimePermission("getClassLoader") 权限调用其 checkPermission 方法,以检查是否允许调用者访问类加载器。

      API 注意:
      此方法不返回 Optional<ClassLoader>,因为必须使用“null”来表示引导类加载器。
      参数:
      name - 要查找的模块的名称
      返回:
      定义模块的 ClassLoader
      抛出:
      IllegalArgumentException - 如果给定名称的模块未在该层或该层的任何父级中定义
      SecurityException - 如果安全经理拒绝
    • toString

      public String  toString()
      返回描述此模块层的字符串。
      重写:
      toString 在类 Object
      返回:
      描述此模块层的可能为空的字符串
    • empty

      public static ModuleLayer  empty()
      返回 empty 层。空层中没有模块。它没有父母。
      返回:
      空层
    • boot

      public static ModuleLayer  boot()
      返回引导层。引导层至少包含一个模块,java.base。它的父级是 empty 层。
      API 注意:
      此方法在启动期间和引导层完全初始化之前返回 null
      返回:
      引导层