作者:hunhun1981
出自:http://blog.csdn.net/hunhun1981/
Vector是在java编程中比较常用的动态数组。一直以为它是个数组的链表,当内存不够用了,就新申请一个capacityIncrement大小的数组,连到原来的链表上。
在仔细阅读源代码后发现,Vector并没有任何链表的性质。它是一个纯粹的数组。当内存不够用时,就重新初始化一个容量较大新数组,然后使用System.arraycopy()函数将原有的数组copy到新的数组当中。
System.arraycopy()是一个由系统平台来实现的函数,这样的系统调用性能是比较高的。
即使如此,我们在写程序时,注意initialCapacity(初始容量)和capacityIncrement(增量)的设置,将会有效的减少重新定义数组并且拷贝数组的次数。
例如:
Vector v = new Vector(10, 10);//初始容量为10,增量10
Integer[] ints = new Integer[11];
for (int i = 0; i < ints.length; i++) {
ints[i] = new Integer(i);
v.addElement(ints[i]);
}
在这里,当v添加第11个Integer的时候,v就会自动创建一个长度为20的数组(当前容量+增量),以后每次装满数组,都会重新按增量追加数组长度。
所以,设置一个合适的初始容量和增量,将会提高Vector的效率。千万别像我一样,把它当做链表。因为链表在增长空间时是不会影响到以前使用的空间和数据的。
我想指出一点,因为Vector中存储的,实际上都是Object变量,大家可以把它理解为指针。重新初始化Vector内置的数组并且拷贝,相当于对一个指针数组进行操作,并不等同于对输入类型的重新分配内存。
就是说Vector的重新分配,不论进行多少次都不涉及到Integer对象的创建,拷贝等工作。它只是重新创建并拷贝“指针”数组,也就是Object数组。
此外,java中有一个容易被忽视的基本概念。当某个对象再没有指向该对象的引用时,垃圾回收器才会自动将其自动释放。不小心使用,很容易给程序造成内存问题。
例如:
Vector v = new Vector(10, 10);//初始容量为10,增量10
Integer[] ints = new Integer[11];
for (int i = 0; i < ints.length; i++) {
ints[i] = new Integer(i);
v.addElement(ints[i]);
}
ints = null;//对它的释放将造成数组元素的释放。但是由于v中还保存有元素的引用,所以这些Integer对象并不会被回收。
我强调这个问题,是因为曾经写过一段代码:
Image img = Image.createImage(”/xxx.png”);
Image img2 = img;
这张图片非常大,在使用完img之后,我释放掉它,然后重新申请另一个图片。于是,内存爆了。因为img2仍然持有xxx.png的引用,所以无法释放。
Vectro中存储的也是引用,所以在使用时应该更加注意编程规范,以免发生类似的问题。其实应该尽量避免使用多个引用。
上面说了这些题外话,正是想警告各位程序员,Vector是一个可变的Object数组,一个引用数组。所以请大家使用时要小心,别想当然的以为它是一个容器,它里面存储的可不是对象,而是引用。
而且,在释放曾经加入到vector的对象时,对象本身并不会被真正释放,得到回收。只是原有的引用无法再使用罢了。
最后还有一点技巧。
应该尽量使用索引获取对象,避免使用IndexOf()方法。把它当做堆栈来使用时更应该注意,要避免使用insertElementAt()方法。
此外,j2me中的Stack类是基于Vector实现的,使用时也要留心。
更多信息,请关注hunhun1981的专栏 。