Java中是否有内存高效的等效于C unions或C++ std::variant的方案?
问题1解决方案(无需自行实现或引入第三方variant类)
完全可以实现,核心方案是将原类中obj的泛型类型T改为Object即可,Java的所有引用类型都继承自Object,天然可以兼容你需要的三种存储场景:业务值T、Element实例引用、Integer类型的索引值。
使用时可以通过两种方式区分当前obj存储的内容:
- 如果你能保证业务类型
T不会是Element或Integer类型,直接用instanceof关键字判断即可:
// 判断逻辑示例 if (obj instanceof Element) { Element target = (Element) obj; // 处理Element引用场景 } else if (obj instanceof Integer) { int index = (int) obj; // 处理索引场景 } else { @SuppressWarnings("unchecked") T businessVal = (T) obj; // 处理正常存储T的场景 }
- 如果
T可能和Element/Integer类型重合,你可以复用现有int成员的特殊值做标记,例如预留Integer.MIN_VALUE、Integer.MIN_VALUE+1两个特殊值:- 当
i == Integer.MIN_VALUE时,obj存储的是Element引用 - 当
i == Integer.MIN_VALUE+1时,obj存储的是索引值 - 其他情况
obj存储的是T类型业务值,i为正常的业务数值
- 当
问题2 最高内存效率的实现方案
因为你需要创建大量Element实例,优先选择无额外对象开销、不新增类字段的方案:
- 优先直接将
Element引用存入obj,不要用索引存储的方式:索引需要包装为Integer对象,超出-128~127缓存范围的Integer会创建新对象,每个Integer对象额外占用16字节左右的内存,大量实例下内存开销非常可观,而直接存储Element引用只是用了原有obj的引用位,没有任何额外对象开销。 - 不要为了做类型标记新增额外的成员字段:Java中每个类的int字段会占用4字节,百万级实例下就会多出数MB的不必要开销,优先用前面提到的复用现有
int成员特殊值的方式做标记,完全不需要新增字段。 - 不要用包装类封装
obj的类型:任何额外的包装类都会新增对象头开销,远不如直接用Object类型的obj+类型判断/预留标记位的方案效率高。
按照这个方案实现的Element类和你最初定义的类内存占用几乎完全一致,是当前需求下内存效率最高的实现。
内容的提问来源于stack exchange,提问作者Captain Hatteras
相关产品推荐
相关产品推荐

