Module java.base
Package java.util

Class ResourceBundle.Control

java.lang.Object
java.util.ResourceBundle.Control
封装类:
ResourceBundle

public static class ResourceBundle.Control extends Object
ResourceBundle.Control定义了一组回调方法,这些方法在bundle加载过程中由ResourceBundle.getBundle工厂方法调用。换句话说,ResourceBundle.Control与工厂方法协作加载资源包。回调方法的默认实现提供了工厂方法执行默认行为所需的信息。

ResourceBundle.Control设计用于部署在未命名模块中的应用程序,例如支持非标准格式的资源包或以非传统约定打包本地化资源。当迁移到模块时,ResourceBundleProviderResourceBundle.Control的替代品。调用带有ResourceBundle.Control参数的工厂方法时,将抛出UnsupportedOperationException

除了回调方法外,toBundleNametoResourceName方法主要用于方便实现回调方法。但是,toBundleName方法可以被重写以提供组织和打包本地化资源的不同约定。toResourceName方法是final的,以避免使用错误的资源和类名分隔符。

两个工厂方法,getControl(List)getNoFallbackControl(List),提供实现默认bundle加载过程的ResourceBundle.Control实例的常见变体。

getFormats方法返回的格式和getCandidateLocales方法返回的候选区域必须在所有相同基础bundle的ResourceBundle.getBundle调用中保持一致。否则,ResourceBundle.getBundle方法可能返回意外的bundle。例如,如果getFormats方法仅为第一次调用ResourceBundle.getBundle返回"java.class",第二次调用仅返回"java.properties",那么第二次调用将返回在第一次调用期间缓存的基于类的那个。

如果ResourceBundle.Control实例同时被多个线程使用,则必须是线程安全的。ResourceBundle.getBundle不会同步调用ResourceBundle.Control方法。方法的默认实现是线程安全的。

应用程序可以指定由getControl工厂方法返回的ResourceBundle.Control实例或从ResourceBundle.Control的子类创建的实例,以自定义bundle加载过程。以下是更改默认bundle加载过程的示例。

示例1

以下代码让ResourceBundle.getBundle仅查找基于属性的资源。

import java.util.*;
import static java.util.ResourceBundle.Control.*;
...
ResourceBundle bundle =
  ResourceBundle.getBundle("MyResources", Locale.forLanguageTag("fr-CH"),
                           ResourceBundle.Control.getControl(FORMAT_PROPERTIES));
根据ResourceBundle.getBundle描述中的示例中的资源包,此ResourceBundle.getBundle调用加载MyResources_fr_CH.properties,其父级是MyResources_fr.properties,其父级是MyResources.properties。(MyResources_fr_CH.properties不会被隐藏,但MyResources_fr_CH.class会被隐藏。)

示例2

以下是使用Properties.loadFromXML加载基于XML的资源包的示例。

ResourceBundle rb = ResourceBundle.getBundle("Messages",
    new ResourceBundle.Control() {
        public List<String> getFormats(String baseName) {
            if (baseName == null)
                throw new NullPointerException();
            return Arrays.asList("xml");
        }
        public ResourceBundle newBundle(String baseName,
                                        Locale locale,
                                        String format,
                                        ClassLoader loader,
                                        boolean reload)
                         throws IllegalAccessException,
                                InstantiationException,
                                IOException {
            if (baseName == null || locale == null
                  || format == null || loader == null)
                throw new NullPointerException();
            ResourceBundle bundle = null;
            if (format.equals("xml")) {
                String bundleName = toBundleName(baseName, locale);
                String resourceName = toResourceName(bundleName, format);
                InputStream stream = null;
                if (reload) {
                    URL url = loader.getResource(resourceName);
                    if (url != null) {
                        URLConnection connection = url.openConnection();
                        if (connection != null) {
                            // 禁用缓存以获取重新加载的新数据。
                            connection.setUseCaches(false);
                            stream = connection.getInputStream();
                        }
                    }
                } else {
                    stream = loader.getResourceAsStream(resourceName);
                }
                if (stream != null) {
                    BufferedInputStream bis = new BufferedInputStream(stream);
                    bundle = new XMLResourceBundle(bis);
                    bis.close();
                }
            }
            return bundle;
        }
    });

...

private static class XMLResourceBundle extends ResourceBundle {
    private Properties props;
    XMLResourceBundle(InputStream stream) throws IOException {
        props = new Properties();
        props.loadFromXML(stream);
    }
    protected Object handleGetObject(String key) {
        return props.getProperty(key);
    }
    public Enumeration<String> getKeys() {
        ...
    }
}
API 注意:
ResourceBundle.Control不支持在命名模块中。如果在命名模块中调用带有ResourceBundle.ControlResourceBundle.getBundle方法,该方法将抛出一个UnsupportedOperationException。在命名模块中忽略任何ResourceBundleControlProvider的服务提供者。
自 JDK 版本:
1.6
参见:
  • Field Details

    • FORMAT_DEFAULT

      public static final List<String> FORMAT_DEFAULT
      默认格式List,按照顺序包含字符串"java.class""java.properties"。此List是不可修改的。
      参见:
    • FORMAT_CLASS

      public static final List<String> FORMAT_CLASS
      包含"java.class"的仅类格式List。此List是不可修改的。
      参见:
    • FORMAT_PROPERTIES

      public static final List<String> FORMAT_PROPERTIES
      包含"java.properties"的仅属性格式List。此List是不可修改的。
      参见:
    • TTL_DONT_CACHE

      public static final long TTL_DONT_CACHE
      用于不缓存加载的资源包实例的生存时间常量。
      参见:
    • TTL_NO_EXPIRATION_CONTROL

      public static final long TTL_NO_EXPIRATION_CONTROL
      用于在缓存中禁用加载的资源包实例的到期控制的生存时间常量。
      参见:
  • Constructor Details

    • Control

      protected Control()
      唯一构造函数。(通常由子类构造函数隐式调用。)
  • Method Details

    • getControl

      public static final ResourceBundle.Control getControl(List<String> formats)
      返回一个ResourceBundle.Control,其中getFormats方法返回指定的formatsformats必须等于FORMAT_PROPERTIESFORMAT_CLASSFORMAT_DEFAULT之一。此方法返回的ResourceBundle.Control实例是单例且线程安全的。

      指定FORMAT_DEFAULT等同于实例化ResourceBundle.Control类,只是此方法返回一个单例。

      参数:
      formats - ResourceBundle.Control.getFormats方法要返回的格式
      返回:
      支持指定formatsResourceBundle.Control
      抛出:
      NullPointerException - 如果formatsnull
      IllegalArgumentException - 如果formats未知
    • getNoFallbackControl

      public static final ResourceBundle.Control getNoFallbackControl(List<String> formats)
      返回一个ResourceBundle.Control,其中getFormats方法返回指定的formatsgetFallbackLocale方法返回nullformats必须等于FORMAT_PROPERTIESFORMAT_CLASSFORMAT_DEFAULT之一。此方法返回的ResourceBundle.Control实例是单例且线程安全的。
      参数:
      formats - ResourceBundle.Control.getFormats方法要返回的格式
      返回:
      支持指定formats且不支持回退LocaleResourceBundle.Control
      抛出:
      NullPointerException - 如果formatsnull
      IllegalArgumentException - 如果formats未知
    • getFormats

      public List<String> getFormats(String baseName)
      返回一个包含用于加载给定baseName的资源包的格式的String ListResourceBundle.getBundle工厂方法尝试按照列表指定的顺序加载资源包。此方法返回的列表必须至少有一个String。预定义的格式为基于类的资源包的"java.class"和基于属性的资源包的"java.properties"。以"java."开头的字符串保留供将来扩展使用,不得被应用程序定义的格式使用。

      不要求返回不可变(不可修改)的List。但是,在getFormats返回后,返回的List不得发生变化。

      默认实现返回FORMAT_DEFAULT,以便ResourceBundle.getBundle工厂方法首先查找基于类的资源包,然后查找基于属性的资源包。

      参数:
      baseName - 资源包的基本名称,完全限定的类名
      返回:
      包含用于加载资源包的格式的String List
      抛出:
      NullPointerException - 如果baseName为null
      参见:
    • getCandidateLocales

      public List<Locale> getCandidateLocales(String baseName, Locale locale)
      返回baseNamelocale的候选区域设置Locale列表。每次工厂方法ResourceBundle.getBundle尝试为目标Locale查找资源包时,都会调用此方法。

      候选区域设置的顺序也对应于运行时资源查找路径(也称为父级链),如果候选区域设置的相应资源包存在且它们的父级未由加载的资源包本身定义。列表的最后一个元素必须是根区域设置,如果希望将基本包作为父级链的终端。

      如果给定的区域设置等于Locale.ROOT(根区域设置),则必须返回一个仅包含根LocaleList。在这种情况下,ResourceBundle.getBundle工厂方法仅加载基本包作为生成的资源包。

      不要求返回一个不可变(不可修改)的List。但是,在由getCandidateLocales返回之后,返回的List不能被修改。

      默认实现返回包含LocaleList,使用下面描述的规则。在下面的描述中,LSCV分别表示非空语言、脚本、国家和变体。例如,[L, C]表示只有语言和国家有非空值的Locale。形式L("xx")表示(非空)语言值为"xx"。对于所有情况,最终组件值为空字符串的Locale将被省略。

      1. 对于具有空脚本值的输入Locale,通过逐个省略最终组件来附加候选Locale,如下所示:
        • [L, C, V]
        • [L, C]
        • [L]
        • Locale.ROOT
      2. 对于具有非空脚本值的输入Locale,通过省略最终组件直到语言来附加候选Locale,然后附加从具有国家和变体的Locale生成的候选项:
        • [L, S, C, V]
        • [L, S, C]
        • [L, S]
        • [L, C, V]
        • [L, C]
        • [L]
        • Locale.ROOT
      3. 对于具有由下划线分隔的多个子标记组成的变体值的输入Locale,通过逐个省略变体子标记来生成候选Locale,然后将它们插入到原始列表中具有完整变体值的Locale的每次出现之后。例如,如果变体由两个子标记V1V2组成:
        • [L, S, C, V1, V2]
        • [L, S, C, V1]
        • [L, S, C]
        • [L, S]
        • [L, C, V1, V2]
        • [L, C, V1]
        • [L, C]
        • [L]
        • Locale.ROOT
      4. 中文的特殊情况。当输入的Locale具有语言"zh"(中文)且脚本值为空时,根据国家可能提供"简体"("Hans")或"繁体"("Hant")。当国家是"CN"(中国)或"SG"(新加坡)时,提供"简体"。当国家是"HK"(中国香港特别行政区)、"MO"(中国澳门特别行政区)或"TW"(台湾)时,提供"繁体"。对于所有其他国家或当国家为空时,不提供脚本。例如,对于Locale("zh", "CN"),候选列表将是:
        • [L("zh"), S("Hans"), C("CN")]
        • [L("zh"), S("Hans")]
        • [L("zh"), C("CN")]
        • [L("zh")]
        • Locale.ROOT
        对于Locale("zh", "TW"),候选列表将是:
        • [L("zh"), S("Hant"), C("TW")]
        • [L("zh"), S("Hant")]
        • [L("zh"), C("TW")]
        • [L("zh")]
        • Locale.ROOT
      5. 挪威语的特殊情况。Locale("no", "NO", "NY")Locale("nn", "NO")都表示挪威尼诺斯克。当区域设置的语言是"nn"时,首先生成标准的候选列表直到[L("nn")],然后添加以下候选项:
        • [L("no"), C("NO"), V("NY")]
        • [L("no"), C("NO")]
        • [L("no")]
        • Locale.ROOT
        如果区域设置正好是Locale("no", "NO", "NY"),则首先转换为Locale("nn", "NO"),然后按照上述过程进行。

        此外,Java将语言"no"视为挪威博克马尔语"nb"的同义词。除了单个情况Locale("no", "NO", "NY")(在上面处理),当输入的Locale具有语言"no"或"nb"时,具有语言代码"no"和"nb"的候选Locale将交错,首先使用请求的语言,然后使用其同义词。例如,Locale("nb", "NO", "POSIX")生成以下候选列表:

        • [L("nb"), C("NO"), V("POSIX")]
        • [L("no"), C("NO"), V("POSIX")]
        • [L("nb"), C("NO")]
        • [L("no"), C("NO")]
        • [L("nb")]
        • [L("no")]
        • Locale.ROOT
        Locale("no", "NO", "POSIX")将生成相同的列表,只是具有"no"的区域设置将出现在具有"nb"的相应区域设置之前。

      默认实现使用一个ArrayList,覆盖实现可能在将其返回给调用者之前修改它。但是,子类在由getCandidateLocales返回之后不能修改它。

      例如,如果给定的baseName是"Messages",给定的localeLocale("ja", "", "XX"),那么将返回一个Locale列表:

           Locale("ja", "", "XX")
           Locale("ja")
           Locale.ROOT
       
      并且如果找到了"ja"和""Locale的资源包,那么运行时资源查找路径(父级链)是:
      
           Messages_ja -> Messages
       
      参数:
      baseName - 资源包的基本名称,完全限定的类名
      locale - 想要资源包的区域设置
      返回:
      给定locale的候选Locale列表
      抛出:
      NullPointerException - 如果baseNamelocalenull
    • getFallbackLocale

      public Locale getFallbackLocale(String baseName, Locale locale)
      返回一个Locale,用作ResourceBundle.getBundle工厂方法进一步资源包搜索的回退区域设置。每当对于baseNamelocale未找到任何结果资源包时(其中区域设置是ResourceBundle.getBundle的参数或此方法返回的先前回退区域设置),都会从工厂方法中调用此方法。

      如果不希望进行进一步的回退搜索,则该方法返回null

      默认实现如果给定的locale不是默认区域设置,则返回默认Locale。否则,返回null

      参数:
      baseName - 资源包的基本名称,一个完全限定的类名,ResourceBundle.getBundle无法找到任何资源包(除了基本包)的基础包名
      locale - ResourceBundle.getBundle无法找到任何资源包(除了基本包)的Locale
      返回:
      用于回退搜索的Locale,如果不希望进行进一步的回退搜索,则返回null
      抛出:
      NullPointerException - 如果baseNamelocalenull
    • newBundle

      public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException
      为给定的包名称、格式和区域设置实例化资源包,必要时使用给定的类加载器。如果给定参数没有可用的资源包,则此方法返回null。如果由于意外错误而无法实例化资源包,则必须通过抛出ErrorException来报告错误,而不仅仅返回null

      如果reload标志为true,表示由于先前加载的资源包已过期而调用此方法。

      实现要求:
      命名模块中的资源包受到Module.getResourceAsStream指定的封装规则的约束。对于给定类加载器可见的命名模块中的资源包,在资源文件对应的资源包的包是无条件打开时可访问。

      默认实现实例化ResourceBundle如下。

      参数:
      baseName - 资源包的基本包名称,完全限定的类名
      locale - 应实例化资源包的区域设置
      format - 要加载的资源包格式
      loader - 用于加载包的ClassLoader
      reload - 指示包重新加载的标志;如果重新加载已过期的资源包,则为true,否则为false
      返回:
      资源包实例,如果找不到则为null
      抛出:
      NullPointerException - 如果bundleNamelocaleformatloadernull,或者toBundleName返回null
      IllegalArgumentException - 如果format未知,或者对于给定参数找到的资源包包含格式错误的数据。
      ClassCastException - 如果加载的类无法转换为ResourceBundle
      IllegalAccessException - 如果类或其无参构造函数不可访问。
      InstantiationException - 如果由于其他原因类的实例化失败。
      ExceptionInInitializerError - 如果此方法引发的初始化失败。
      SecurityException - 如果存在安全管理器并且拒绝创建新实例。有关详细信息,请参见Class.newInstance()
      IOException - 如果使用任何I/O操作读取资源时发生错误
      参见:
    • getTimeToLive

      public long getTimeToLive(String baseName, Locale locale)
      返回在此ResourceBundle.Control下加载的资源包的存活时间(TTL)值。正值的存活时间值指定资源包可以在缓存中保持的毫秒数,而无需根据构建它的源数据进行验证。值0表示每次从缓存中检索时必须验证包。 TTL_DONT_CACHE指定加载的资源包不放入缓存。 TTL_NO_EXPIRATION_CONTROL指定加载的资源包放入缓存中,且无过期控制。

      过期仅影响由ResourceBundle.getBundle工厂方法进行的包加载过程。也就是说,如果工厂方法在缓存中找到已过期的资源包,则工厂方法调用needsReload方法来确定是否需要重新加载资源包。如果needsReload返回true,则从缓存中移除缓存的资源包实例。否则,实例保留在缓存中,并使用此方法返回的新TTL值进行更新。

      所有缓存的资源包都可能因运行时环境的内存限制而从缓存中移除。返回一个较大的正值并不意味着将加载的资源包锁定在缓存中。

      默认实现返回TTL_NO_EXPIRATION_CONTROL

      参数:
      baseName - 指定过期值的资源包的基本包名称。
      locale - 指定过期值的资源包的区域设置。
      返回:
      用于使缓存中加载的包过期的时间(0或从缓存时间开始的正毫秒偏移量),TTL_NO_EXPIRATION_CONTROL以禁用过期控制,或TTL_DONT_CACHE以禁用缓存。
      抛出:
      NullPointerException - 如果baseNamelocalenull
    • needsReload

      public boolean needsReload(String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime)
      根据给定的loadTime或其他标准,确定缓存中已过期的bundle是否需要重新加载。如果需要重新加载,则该方法返回true;否则返回falseloadTime是自 Calendar Epoch以来的毫秒偏移量。

      调用ResourceBundle.getBundle工厂方法时,该方法在当前调用所使用的ResourceBundle.Control实例上调用,而不是在最初加载资源包的调用中使用的实例上调用。

      默认实现比较loadTime和资源包的源数据的最后修改时间。如果确定自loadTime以来源数据已被修改,则返回true。否则,返回false。此实现假定给定的format如果不是默认格式之一"java.class""java.properties",则与其文件后缀相同。

      参数:
      baseName - 资源包的基本包名称,完全限定的类名
      locale - 应实例化资源包的区域设置
      format - 要加载的资源包格式
      loader - 用于加载包的ClassLoader
      bundle - 在缓存中已过期的资源包实例
      loadTime - 将bundle加载并放入缓存时的时间
      返回:
      如果需要重新加载已过期的包,则返回true;否则返回false
      抛出:
      NullPointerException - 如果baseNamelocaleformatloaderbundlenull
    • toBundleName

      public String toBundleName(String baseName, Locale locale)
      将给定的baseNamelocale转换为资源包名称。此方法从newBundleneedsReload方法的默认实现中调用。

      此实现返回以下值:

           baseName + "_" + language + "_" + script + "_" + country + "_" + variant
       
      其中languagescriptcountryvariant分别是locale的语言、脚本、国家和变体值。空字符串的最终组件值将与前面的“_”一起省略。当脚本为空时,脚本值将与前面的“_”一起省略。如果所有值都是空字符串,则返回baseName

      例如,如果baseName"baseName"localeLocale("ja", "", "XX"),则返回"baseName_ja_ _XX"。如果给定的locale是Locale("en"),则返回"baseName_en"

      覆盖此方法允许应用程序在本地化资源的组织和打包中使用不同的约定。

      参数:
      baseName - 资源包的基本名称,完全限定的类名
      locale - 应加载资源包的区域设置
      返回:
      资源包的包名称
      抛出:
      NullPointerException - 如果baseNamelocalenull
      参见:
    • toResourceName

      public final String toResourceName(String bundleName, String suffix)
      将给定的bundleName转换为ClassLoader.getResource方法所需的形式,方法是将bundleName中所有'.'的出现替换为'/',并附加一个'.'和给定的文件suffix。例如,如果bundleName"foo.bar.MyResources_ja_JP"suffix"properties",则返回"foo/bar/MyResources_ja_JP.properties"
      参数:
      bundleName - 资源包名称
      suffix - 文件类型后缀
      返回:
      转换后的资源名称
      抛出:
      NullPointerException - 如果bundleNamesuffixnull