首先,要明白到下面的一些知识点:
1、collection是hashmap和array的接口
2、hashmap中的元素是没有次序的,而array是有的
3、hashmap转化为array对象时,里面元素的排列顺序与用Iterator遍历原hashmap时的顺序一样。
4、新创建的array对象与参数列表中的列表对象对应起来;collection与原HashMap对应起来(所谓:对应就是某个对象的修改会自动引起另外一个对象的改变)
下面谈谈怎么将一个hashmap对象转化为array对象
首先,将hashmap转化为collection对象
通过:values()方法
为什么可以这么做:
留意到hashmap类,中有一个成员变量:
transient volatile Collection<V> values = null;
再留意hashmap类,中有一个成员函数:
public Collection<V> values() {
Collection<V> vs = values;
return (vs != null ? vs : (values = new Values()));
}
返回的正正是hashmap对象的value值。
说到这里,应该可以留意到你现在手上拿的仅仅是一个collection对象,离我们的目标还有一步之遥。
为了使到一个collection对象变成一个array对象,我们使用以下的方法:
<T> T[] toArray(T[] a);
对于这个方法,我们有必要说明一下。并且举一些例子来验证一下我的理解。
首先,可以看看collection接口的源码中关于<T> T[] toArray(T[] a);的诉述:
(英文还可以的同学建议直接看原版的介绍,因为本人的英语水平有限,可能翻译得不是太理想。怕误人子弟啊!)
/**
* Returns an array containing all of the elements in this collection;
* the runtime type of the returned array is that of the specified array.
* If the collection fits in the specified array, it is returned therein.
* Otherwise, a new array is allocated with the runtime type of the
* specified array and the size of this collection.
*
* <p>If this collection fits in the specified array with room to spare
* (i.e., the array has more elements than this collection), the element
* in the array immediately following the end of the collection is set to
* <tt>null</tt>. (This is useful in determining the length of this
* collection <i>only</i> if the caller knows that this collection does
* not contain any <tt>null</tt> elements.)
*
* <p>If this collection makes any guarantees as to what order its elements
* are returned by its iterator, this method must return the elements in
* the same order.
*
* <p>Like the {@link #toArray()} method, this method acts as bridge between
* array-based and collection-based APIs. Further, this method allows
* precise control over the runtime type of the output array, and may,
* under certain circumstances, be used to save allocation costs.
*
* <p>Suppose <tt>x</tt> is a collection known to contain only strings.
* The following code can be used to dump the collection into a newly
* allocated array of <tt>String</tt>:
*
* <pre>
* String[] y = x.toArray(new String[0]);</pre>
*
* Note that <tt>toArray(new Object[0])</tt> is identical in function to
* <tt>toArray()</tt>.
*
* @param a the array into which the elements of this collection are to be
* stored, if it is big enough; otherwise, a new array of the same
* runtime type is allocated for this purpose.
* @return an array containing all of the elements in this collection
* @throws ArrayStoreException if the runtime type of the specified array
* is not a supertype of the runtime type of every element in
* this collection
* @throws NullPointerException if the specified array is null
*/
上面的介绍大概是这个意思:
这个方法可以返回一个包含了调用这个方法的collection对象中所有元素的新队列对象;而这个新的队列对象中元素的类型是根据参数列表中的队列对象的元素类型决定的。如果原来collection对象的元素个数不超过参数列表中的队列对象的元素个数,就不会另外创建一个新的列表对象,而是将collection对象中的全部元素放到参数列表中的队列对象去。否则,就会先创建一个元素类型与参数列表中的队列对象一样而元素个数与原collection元素一致的队列对象,再赋值进去。另外,如果参数列表中的队列对象元素个数超过原collection的,系统会用null元素将剩下来的位置填满。
除此之外,新的array对象中的元素的排列顺序与使用一个iterator遍历原collection对象中的元素的顺序一致。
和toArray()方法一样,这个方法实现了将collection对象转化为array对象。但是,比起toArray()方法,这个方法可以更加准确地控制新队列对象的元素类型,并且可以在特定的情况下节约内存。因为,当参数列表中的队列对象足够大的时候,就不需要额外申请空间来保存新的队列对象,而是直接使用原来的空间就可以了。
例如,x是一个保存string元素的collection对象。下面的代码就展示了我们如何使用一个新分配空间的队列对象来保存一个collection对象:
String[] y = x.toArray(new String[0]);
注意:
toArray(new Object[0])和toArray()的作用一样。
*
* @参数 a 通过队列对象a的元素类型指定新转化所得的队列对象的元素类型。如果队列对象a的元素不小于待转化的collection对象的元素个数时,不需要另外分配内存空间,直接将原collection对象的元素都放进队列对象a中去。
* @返回一个持有原collection对象所有元素的队列对象
* @throws ArrayStoreException 元素类型冲突
* @throws NullPointerException 参数列表中的队列对象为空
实验1:
目的:验证参数列表中的队列对象的元素个数,对是否重新分配空间,保存新队列对象的影响
源码1:
HashMap<String, String>test=new HashMap<String, String>();
test.put("a","a's value");
test.put("b", "b's value");
String []test1=new String[3];
String[] test2=test.values().toArray(test1);
System.out.println("test1:");
System.out.println(test1.length);
for(String v:test1){
System.out.println(v);
}
System.out.println("test2:");
System.out.println(test2.length);
for(String v:test2){
System.out.println(v);
}
console:
test1:
3
b's value
a's value
null
test2:
3
b's value
a's value
null
分析:
对比上面可见:参数列表中的队列对象test1和目标队列对象test2都指向了新队列对象,即他们共有了内存空间不用另外分配。又因为参数列表中的队列对象test1的元素个数超过原collection对象的元素个数,所以在后面填充null元素。
源码2:
HashMap<String, String>test=new HashMap<String, String>();
test.put("a","a's value");
test.put("b", "b's value");
String []test1=new String[1];
String[] test2=test.values().toArray(test1);
System.out.println("test1:");
System.out.println(test1.length);
for(String v:test1){
System.out.println(v);
}
System.out.println("test2:");
System.out.println(test2.length);
for(String v:test2){
System.out.println(v);
}
console:
test1:
1
null
test2:
2
b's value
a's value
分析:
对比上面可见:参数列表中的队列对象test1没有获得任何元素,而test2中有。可见,已经分配了新的内存空间了。
实验二:
目的:发现两个队列对象之间的对应关系;collection对象与原hashmap对象的对应关系;但是前后两组对应对象之间不会相互影响
源码:
HashMap<String, String>test=new HashMap<String, String>();
test.put("a","a's value");
test.put("b", "b's value");
String []test1=new String[2];
Collection<String>variable=test.values();
String[] test2=variable.toArray(test1);
variable.remove("b's value");
System.out.println("colletction object:"+variable.toString());
System.out.println("Hashmap object:"+test);
// test.values().toArray(test1);
System.out.println("test1:");
System.out.println(test1.length);
for(String v:test1){
System.out.println(v);
}
System.out.println("test2:");
System.out.println(test2.length);
for(String v:test2){
System.out.println(v);
}
test2[0]="kaiwii modify!";
System.out.println("test2:");
System.out.println(test2.length);
for(String v:test2){
System.out.println(v);
}
System.out.println("test1:");
System.out.println(test1.length);
for(String v:test1){
System.out.println(v);
}
System.out.println(test.toString());
System.out.println("whether test contain the modified value:"+test.containsValue("kaiwii modify!"));
console:
colletction object:[a's value]
Hashmap object:{a=a's value}
test1:
2
b's value
a's value
test2:
2
b's value
a's value
test2:
2
kaiwii modify!
a's value
test1:
2
kaiwii modify!
a's value
{a=a's value}
whether test contain the modified value:false