我的问题是-这是意料之中的,还是这是某种JVM错误?
判断最新的javadoc(JDK 22u),"这些值是单例"没有提到.因为我们可以更简单地陈述你的情况,而不会把堆问题带进go :
// bug claim:
ZoneId a = ZoneId.of("Europe/Kiev");
ZoneId b = ZoneId.of("Europe/Kiev");
System.out.println(a == b); // should print true!
...但这会打印false
,因此这意味着支持ZoneId.of
do not的机制会导致单例ZoneId
对象--要么JDK不存在预缓存的每个可能的ZoneID对象,要么ZoneId.of本身无法建立缓存.
或者这是某种JVM错误?
Java Lang Spec和Java Virtual Machine Spec不会(或不应该)提及这方面的任何内容,因为它不在java.lang
包或子包中,对于语言本身至关重要的任何类型都需要在JLS/JVMS中提及.
因此,javadoc是该规范的规范来源.
一百零二
作为参考,current JDK22u sources of ZoneId.
有一句话是这样的:
* The ID is unique within the system.
关于ZoneID本身,might解释为:"ID"这里是"An Instance of ZoneID"的缩写,但这并不是对这一行的明显解释;他们谈论的是,例如,Europe/Kiev
作为一个概念不能同时导致对其所指时区的两种不同概念.文档的这一部分不是关于实现细节级别的概念...并且该系统将缓存该概念,以便不需要存在两个实例.
它does包含一个附加条款,即实例将被视为ValueBased(在主javadoc的末尾):您不应该以任何方式假设例如==
会做什么(换句话说,他们明确保留引入某种缓存机制的权利,或者这些将成为直接的valhalla风格的值类,首先不具有标识).但这只是简单地规定你不应该依赖either:你不能依赖于重复调用ZoneId.of("Europe/Kiev")
返回不同的对象,你可以依赖于这样的调用返回相同的对象.在代码方面,您根本不应该考虑对象的ZoneId实例.
的溶液
如果您的分析器报告强烈建议减少ZoneID实例的数量将有所帮助,那么API文档将授予您缓存这些实例的权限:
private static final Map<String, ZoneId> CACHED_ZONE_IDS = new HashMap<>();
public static ZoneId cachedOf(String id) {
return CACHED_ZONE_IDS.computeIfAbsent(id, ZoneId::of);
}
如果您担心需要从缓存的 map 中‘超时’不再使用的ZoneIds,您可以查看番石榴的CacheBuilder,但在这里这似乎有点过头了;我将其保留为上面的3行代码.