- 封装类:
-
ResourceBundle
ResourceBundle.Control
定义了一组回调方法,这些方法在bundle加载过程中由ResourceBundle.getBundle
工厂方法调用。换句话说,ResourceBundle.Control
与工厂方法协作加载资源包。回调方法的默认实现提供了工厂方法执行默认行为所需的信息。
ResourceBundle.Control
设计用于部署在未命名模块中的应用程序,例如支持非标准格式的资源包或以非传统约定打包本地化资源。当迁移到模块时,ResourceBundleProvider
是ResourceBundle.Control
的替代品。调用带有ResourceBundle.Control
参数的工厂方法时,将抛出UnsupportedOperationException
。
除了回调方法外,toBundleName
和toResourceName
方法主要用于方便实现回调方法。但是,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.Control
的ResourceBundle.getBundle
方法,该方法将抛出一个UnsupportedOperationException
。在命名模块中忽略任何ResourceBundleControlProvider
的服务提供者。 - 自 JDK 版本:
- 1.6
- 参见:
-
Field Summary
Modifier and TypeFieldDescription仅包含类的格式List
,包含"java.class"
。默认格式List
,按照顺序包含字符串"java.class"
和"java.properties"
。仅包含属性的格式List
,包含"java.properties"
。static final long
不缓存加载的资源包实例的存活时间常量。static final long
禁用缓存中加载的资源包实例的到期控制的存活时间常量。 -
Constructor Summary
-
Method Summary
Modifier and TypeMethodDescriptiongetCandidateLocales
(String baseName, Locale locale) 返回baseName
和locale
的候选区域List
。static final ResourceBundle.Control
getControl
(List<String> formats) getFallbackLocale
(String baseName, Locale locale) 返回一个Locale
,用作ResourceBundle.getBundle
工厂方法进一步搜索资源包的回退区域。getFormats
(String baseName) 返回一个包含用于加载给定baseName
的资源包的格式的List
。static final ResourceBundle.Control
getNoFallbackControl
(List<String> formats) long
getTimeToLive
(String baseName, Locale locale) 返回加载在此ResourceBundle.Control
下的资源包实例的存活时间(TTL)值。boolean
needsReload
(String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime) 根据loadTime
给出的加载时间或其他标准确定缓存中过期的bundle
是否需要重新加载。newBundle
(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) 根据必要情况使用给定的类加载器为给定格式和区域设置实例化资源包的给定bundle名称。toBundleName
(String baseName, Locale locale) 将给定的baseName
和locale
转换为bundle名称。final String
toResourceName
(String bundleName, String suffix)
-
Field Details
-
FORMAT_DEFAULT
默认格式List
,按照顺序包含字符串"java.class"
和"java.properties"
。此List
是不可修改的。- 参见:
-
FORMAT_CLASS
包含"java.class"的仅类格式List
。此List
是不可修改的。- 参见:
-
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
返回一个ResourceBundle.Control
,其中getFormats
方法返回指定的formats
。formats
必须等于FORMAT_PROPERTIES
、FORMAT_CLASS
或FORMAT_DEFAULT
之一。此方法返回的ResourceBundle.Control
实例是单例且线程安全的。指定
FORMAT_DEFAULT
等同于实例化ResourceBundle.Control
类,只是此方法返回一个单例。- 参数:
-
formats
-ResourceBundle.Control.getFormats
方法要返回的格式 - 返回:
-
支持指定
formats
的ResourceBundle.Control
- 抛出:
-
NullPointerException
- 如果formats
为null
-
IllegalArgumentException
- 如果formats
未知
-
getNoFallbackControl
返回一个ResourceBundle.Control
,其中getFormats
方法返回指定的formats
,getFallbackLocale
方法返回null
。formats
必须等于FORMAT_PROPERTIES
、FORMAT_CLASS
或FORMAT_DEFAULT
之一。此方法返回的ResourceBundle.Control
实例是单例且线程安全的。- 参数:
-
formats
-ResourceBundle.Control.getFormats
方法要返回的格式 - 返回:
-
支持指定
formats
且不支持回退Locale
的ResourceBundle.Control
- 抛出:
-
NullPointerException
- 如果formats
为null
-
IllegalArgumentException
- 如果formats
未知
-
getFormats
返回一个包含用于加载给定baseName
的资源包的格式的String
List
。ResourceBundle.getBundle
工厂方法尝试按照列表指定的顺序加载资源包。此方法返回的列表必须至少有一个String
。预定义的格式为基于类的资源包的"java.class"
和基于属性的资源包的"java.properties"
。以"java."
开头的字符串保留供将来扩展使用,不得被应用程序定义的格式使用。不要求返回不可变(不可修改)的
List
。但是,在getFormats
返回后,返回的List
不得发生变化。默认实现返回
FORMAT_DEFAULT
,以便ResourceBundle.getBundle
工厂方法首先查找基于类的资源包,然后查找基于属性的资源包。- 参数:
-
baseName
- 资源包的基本名称,完全限定的类名 - 返回:
-
包含用于加载资源包的格式的
String
List
- 抛出:
-
NullPointerException
- 如果baseName
为null - 参见:
-
getCandidateLocales
返回baseName
和locale
的候选区域设置Locale
列表。每次工厂方法ResourceBundle.getBundle
尝试为目标Locale
查找资源包时,都会调用此方法。候选区域设置的顺序也对应于运行时资源查找路径(也称为父级链),如果候选区域设置的相应资源包存在且它们的父级未由加载的资源包本身定义。列表的最后一个元素必须是根区域设置,如果希望将基本包作为父级链的终端。
如果给定的区域设置等于
Locale.ROOT
(根区域设置),则必须返回一个仅包含根Locale
的List
。在这种情况下,ResourceBundle.getBundle
工厂方法仅加载基本包作为生成的资源包。不要求返回一个不可变(不可修改)的
List
。但是,在由getCandidateLocales
返回之后,返回的List
不能被修改。默认实现返回包含
Locale
的List
,使用下面描述的规则。在下面的描述中,L,S,C和V分别表示非空语言、脚本、国家和变体。例如,[L, C]表示只有语言和国家有非空值的Locale
。形式L("xx")表示(非空)语言值为"xx"。对于所有情况,最终组件值为空字符串的Locale
将被省略。- 对于具有空脚本值的输入
Locale
,通过逐个省略最终组件来附加候选Locale
,如下所示:- [L, C, V]
- [L, C]
- [L]
Locale.ROOT
- 对于具有非空脚本值的输入
Locale
,通过省略最终组件直到语言来附加候选Locale
,然后附加从具有国家和变体的Locale
生成的候选项:- [L, S, C, V]
- [L, S, C]
- [L, S]
- [L, C, V]
- [L, C]
- [L]
Locale.ROOT
- 对于具有由下划线分隔的多个子标记组成的变体值的输入
Locale
,通过逐个省略变体子标记来生成候选Locale
,然后将它们插入到原始列表中具有完整变体值的Locale
的每次出现之后。例如,如果变体由两个子标记V1和V2组成:- [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
- 中文的特殊情况。当输入的
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
- 挪威语的特殊情况。
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",给定的locale
是Locale("ja", "", "XX")
,那么将返回一个Locale
列表:Locale("ja", "", "XX") Locale("ja") Locale.ROOT
并且如果找到了"ja"和""Locale
的资源包,那么运行时资源查找路径(父级链)是:Messages_ja -> Messages
- 参数:
-
baseName
- 资源包的基本名称,完全限定的类名 -
locale
- 想要资源包的区域设置 - 返回:
-
给定
locale
的候选Locale
列表 - 抛出:
-
NullPointerException
- 如果baseName
或locale
为null
- 对于具有空脚本值的输入
-
getFallbackLocale
返回一个Locale
,用作ResourceBundle.getBundle
工厂方法进一步资源包搜索的回退区域设置。每当对于baseName
和locale
未找到任何结果资源包时(其中区域设置是ResourceBundle.getBundle
的参数或此方法返回的先前回退区域设置),都会从工厂方法中调用此方法。如果不希望进行进一步的回退搜索,则该方法返回
null
。默认实现如果给定的
locale
不是默认区域设置,则返回默认Locale
。否则,返回null
。- 参数:
-
baseName
- 资源包的基本名称,一个完全限定的类名,ResourceBundle.getBundle
无法找到任何资源包(除了基本包)的基础包名 -
locale
-ResourceBundle.getBundle
无法找到任何资源包(除了基本包)的Locale
- 返回:
-
用于回退搜索的
Locale
,如果不希望进行进一步的回退搜索,则返回null
- 抛出:
-
NullPointerException
- 如果baseName
或locale
为null
-
newBundle
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException 为给定的包名称、格式和区域设置实例化资源包,必要时使用给定的类加载器。如果给定参数没有可用的资源包,则此方法返回null
。如果由于意外错误而无法实例化资源包,则必须通过抛出Error
或Exception
来报告错误,而不仅仅返回null
。如果
reload
标志为true
,表示由于先前加载的资源包已过期而调用此方法。- 实现要求:
-
命名模块中的资源包受到
Module.getResourceAsStream
指定的封装规则的约束。对于给定类加载器可见的命名模块中的资源包,在资源文件对应的资源包的包是无条件打开时可访问。默认实现实例化
ResourceBundle
如下。- 通过调用
toBundleName(baseName, locale)
获取包名称。 - 如果
format
是"java.class"
,则使用给定的类加载器加载由包名称指定的Class
。如果找到并可访问Class
,则实例化ResourceBundle
。如果包类文件的包是无条件打开的,则资源包是可访问的;否则,将抛出IllegalAccessException
。请注意,在此默认实现中,加载基于类的资源包时会忽略reload
标志。 - 如果
format
是"java.properties"
,则调用toResourceName(bundlename, "properties")
获取资源名称。如果reload
为true
,则调用load.getResource
获取用于创建URL
的URLConnection
。此URLConnection
用于禁用底层资源加载层的缓存,并获取InputStream
。否则,调用loader.getResourceAsStream
获取InputStream
。然后,使用InputStream
构造PropertyResourceBundle
。 - 如果
format
既不是"java.class"
也不是"java.properties"
,则抛出IllegalArgumentException
。 - 如果
locale
的语言是旧版或新版的遗留语言代码之一,则根据需要重复加载过程,使用另一种语言的包名称。例如,对于"iw"和"he",相互重复加载过程。
- 通过调用
- 参数:
-
baseName
- 资源包的基本包名称,完全限定的类名 -
locale
- 应实例化资源包的区域设置 -
format
- 要加载的资源包格式 -
loader
- 用于加载包的ClassLoader
-
reload
- 指示包重新加载的标志;如果重新加载已过期的资源包,则为true
,否则为false
- 返回:
-
资源包实例,如果找不到则为
null
。 - 抛出:
-
NullPointerException
- 如果bundleName
、locale
、format
或loader
为null
,或者toBundleName
返回null
-
IllegalArgumentException
- 如果format
未知,或者对于给定参数找到的资源包包含格式错误的数据。 -
ClassCastException
- 如果加载的类无法转换为ResourceBundle
-
IllegalAccessException
- 如果类或其无参构造函数不可访问。 -
InstantiationException
- 如果由于其他原因类的实例化失败。 -
ExceptionInInitializerError
- 如果此方法引发的初始化失败。 -
SecurityException
- 如果存在安全管理器并且拒绝创建新实例。有关详细信息,请参见Class.newInstance()
。 -
IOException
- 如果使用任何I/O操作读取资源时发生错误 - 参见:
-
getTimeToLive
返回在此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
- 如果baseName
或locale
为null
-
needsReload
public boolean needsReload(String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime) 根据给定的loadTime
或其他标准,确定缓存中已过期的bundle
是否需要重新加载。如果需要重新加载,则该方法返回true
;否则返回false
。loadTime
是自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
- 如果baseName
、locale
、format
、loader
或bundle
为null
-
toBundleName
将给定的baseName
和locale
转换为资源包名称。此方法从newBundle
和needsReload
方法的默认实现中调用。此实现返回以下值:
baseName + "_" + language + "_" + script + "_" + country + "_" + variant
其中language
、script
、country
和variant
分别是locale
的语言、脚本、国家和变体值。空字符串的最终组件值将与前面的“_”一起省略。当脚本为空时,脚本值将与前面的“_”一起省略。如果所有值都是空字符串,则返回baseName
。例如,如果
baseName
是"baseName"
,locale
是Locale("ja", "", "XX")
,则返回"baseName_ja_ _XX"
。如果给定的locale是Locale("en")
,则返回"baseName_en"
。覆盖此方法允许应用程序在本地化资源的组织和打包中使用不同的约定。
- 参数:
-
baseName
- 资源包的基本名称,完全限定的类名 -
locale
- 应加载资源包的区域设置 - 返回:
- 资源包的包名称
- 抛出:
-
NullPointerException
- 如果baseName
或locale
为null
- 参见:
-
toResourceName
将给定的bundleName
转换为ClassLoader.getResource
方法所需的形式,方法是将bundleName
中所有'.'
的出现替换为'/'
,并附加一个'.'
和给定的文件suffix
。例如,如果bundleName
是"foo.bar.MyResources_ja_JP"
,suffix
是"properties"
,则返回"foo/bar/MyResources_ja_JP.properties"
。- 参数:
-
bundleName
- 资源包名称 -
suffix
- 文件类型后缀 - 返回:
- 转换后的资源名称
- 抛出:
-
NullPointerException
- 如果bundleName
或suffix
为null
-