EnumMap的T[] toArray(T[] a)实现疑问及设计意图咨询
关于EnumMap中
toArray(T[] a)方法的疑问 我发现EnumMap的T[] toArray(T[] var2)实现如下:
public <T> T[] toArray(T[] var1) { int var2 = this.size(); if (var1.length < var2) { var1 = (Object[])((Object[])Array.newInstance(var1.getClass().getComponentType(), var2)); } if (var1.length > var2) { var1[var2] = null; } return (Object[])this.fillEntryArray(var1); }
我无法理解其中if (var1.length > var2) { var1[var2] = null; }的含义。
示例场景
enum myKeys{ONE, TWO, THREE}; EnumMap myEnum = new EnumMap<myKeys, String>(myKeys.class); myEnum.put(myKeys.ONE, "1"); myEnum.put(myKeys.TWO, "2"); myEnum.put(myKeys.THREE, "3"); final Object[] objects = myEnum.entrySet().toArray(new Object[8]); for (Object o: objects) { System.out.println(o); }
输出结果:
ONE=1 TWO=2 THREE=3 null null null null null
现提出两个问题:
- 设计EnumMap的
T[] toArray(T[] a)而非仅用无参toArray()的目的是什么? - 为何要使用
if (var1.length > var2) { var1[var2] = null; }?是否是为了给迭代器标记第N+1个元素为null?
问题解答
1) 带参数toArray(T[] a)的设计目的
这其实是Java集合框架的通用设计逻辑,不止EnumMap如此。无参的toArray()只能返回Object[]类型,如果你想把它强制转换成具体类型(比如Map.Entry[]),大概率会抛出ClassCastException——因为Java数组是协变但强类型的,Object[]无法直接向下转型为子类数组。
而带参数的toArray(T[] a)解决了这些痛点:
- 你可以传入指定类型的数组,方法会直接返回该类型的数组,彻底避免强制转换的风险;
- 如果传入的数组长度足够容纳所有集合元素,方法会直接复用这个数组,不用新建对象,节省内存开销;
- 如果长度不够,方法会自动创建一个对应类型、长度匹配集合大小的新数组,保证返回结果的正确性。
就像你示例里传入了Object[8],因为长度足够,方法就直接用这个数组填充元素,没有额外创建新数组。
2) 设置var1[var2] = null的原因
这是严格遵循Java Collection接口的规范要求。当你传入的数组长度大于集合元素个数(var1.length > var2,其中var2是集合当前的大小)时,必须在有效元素的下一个位置(也就是索引var2处)设置为null,作为有效元素的结束标记。
这个标记的实际作用有这些:
- 对于不清楚集合具体大小的调用者来说,通过这个
null可以快速区分哪些是集合的有效元素,哪些是数组本身多余的空间; - 如果传入的数组原本就有值,这个
null能帮你明确区分集合填充的内容和数组原有内容; - 这是集合框架统一的行为,所有实现Collection接口的类(包括EnumMap的entrySet)都遵循这个规则,保证了API行为的一致性。
你示例里的输出刚好验证了这一点:前三个是集合的有效Entry,第四个位置的null就是官方要求的结束标记,后面的null则是数组本身的初始值。
内容的提问来源于stack exchange,提问作者Yury Finchenko
相关产品推荐
相关产品推荐

