Java.util.Vector提供了向量(Vector)类以实现类似动态数组的功能。在Java语言中是没有指针概念的,但如果能正确灵活地使用指针又确实可以大大提高程序的质量,比如在C、C++中所谓“动态数组”一般都由指针来实现。为了弥补这点缺陷,Java提供了丰富的类库来方便编程者使用,Vector类便是其中之一。事实上,灵活使用数组也可完成向量类的功能,但向量类中提供的大量方法大大方便了用户的使用。
相对于ArrayList来说,Vector线程是安全的,也就是说是同步的
创建了一个向量类的对象后,可以往其中随意地插入不同的类的对象,既不需顾及类型也不需预先选定向量的容量,并可方便地进行查找。对于预先不知或不愿预先定义数组大小,并需频繁进行查找、插入和删除工作的情况,可以考虑使用向量类。向量类提供了三种构造方法:
public vector()
public vector(int initialcapacity,int capacityIncrement)
public vector(int initialcapacity)
使用*种方法,系统会自动对向量对象进行管理。若使用后两种方法,则系统将根据参数initialcapacity设定向量对象的容量(即向量对象可存储数据的大小),当真正存放的数据个数超过容量时,系统会扩充向量对象的存储容量。
参数capacityIncrement给定了每次扩充的扩充值。当capacityIncrement为0时,则每次扩充一倍。利用这个功能可以优化存储。在Vector类中提供了各种方法方便用户使用:
插入功能(1)public final synchronized void addElement(Object obj)
将obj插入向量的尾部。obj可以是任何类的对象。对同一个向量对象,可在其中插入不同类的对象。但插入的应是对象而不是数值,所以插入数值时要注意将数值转换成相应的对象。
例 要插入一个整数1时,不要直接调用v1.addElement(1),正确的方法为:
Vector v1=new Vector();
Integer integer1=new Integer(1);
v1.addElement(integer1);
(2)public final synchronized void setElementAt(object obj,int index)
将index处的对象设成obj,原来的对象将被复盖。
(3)public final synchronized void insertElementAt(Object obj,int index)
在index指定的位置插入obj,原来对象以及此后的对象依次往后顺延。
删除功能(1)public final synchronized void removeElement(Object obj)
从向量中删除obj。若有多个存在,则从向量头开始试,删除找到的*与obj相同的向量成员。
(2)public final synchronized void removeAllElement()
删除向量中所有的对象。
(3)public final synchronized void removeElementlAt(int index)
删除index所指的地方的对象。
查询搜索(1)public final int indexOf(Object obj)
从向量头开始搜索obj,返回所遇到的*obj对应的下标,若不存在此obj,返回-1。
(2)public final synchronized int indexOf(Object obj,int index)
从index所表示的下标处开始搜索obj。
(3)public final int lastIndexOf(Object obj)
从向量尾部开始逆向搜索obj。
(4)public final synchronized int lastIndexOf(Object obj,int index)
从index所表示的下标处由尾至头逆向搜索obj。
(5)public final synchronized Object firstElement()
获取向量对象中的*obj。
(6)public final synchronized Object lastelement()
获取向量对象中的较后一个obj。
举例说明了解了向量的最基本的方法后,我们来看一下例子VectorApp.java。
例 VectorApp.java
import java.util.Vector;
import java.lang.*;
//这一句不应该要,但原文如此
import java.util.Enumeration;
public class VectorApp
{
public static void main(String[] args)
{
Vector v1=new Vector();
Integer integer1=new Integer(1);
v1.addElement("one");
//加入的为字符串对象
v1.addElement(integer1);
v1.addElement(integer1);
//加入的为Integer的对象
v1.addElement("two");
v1.addElement(new Integer(2));
v1.addElement(integer1);
v1.addElement(integer1);
System.out.println("The vector v1 is:nt"+v1);
//将v1转换成字符串并打印
v1.insertElementAt("three",2);
v1.insertElementAt(new Float(3.9),3);
System.out.println("The vector v1(used method insertElementAt())is:nt "+v1);
//往指定位置插入新的对象,指定位置后的对象依次往后顺延
v1.setElementAt("four",2);
System.out.println("The vector v1(used method setElementAt())is:nt "+v1);
//将指定位置的对象设置为新的对象
v1.removeElement(integer1);
//从向量对象v1中删除对象integer1由于
存在多个integer1所以从头开始
找,删除找到的*integer1
Enumeration enum=v1.elements();
System.out.print("The vector v1(used method removeElement())is:");
while(enum.hasMoreElements())
System.out.print(enum.nextElement()+" ");
System.out.println();
//使用枚举类(Enumeration)的方法来获取向量对象的每个元素
System.out.println("The position of object 1(top-to-bottom):"
+ v1.indexOf(integer1));
System.out.println("The position of object 1(tottom-to-top):"
+v1.lastIndexOf(integer1));
//按不同的方向查找对象integer1所处的位置
v1.setSize(4);
System.out.println("The new vector(resized the vector)is:"+v1);
//重新设置v1的大小,多余的元素被行弃
}
}
运行结果:
E:java01>java VectorApp
The vector v1 is:
[one,1,1,two,2,1,1]
The vector v1(used method insertElementAt())is:
[one,1,three,3.9,1,two,2,1,1]
The vector v1(used method setElementAt()) is:
[one,1,four,3.9,1,two,2,1,1]
The vector v1(used method removeElement())is:
one four 3.9 1 two 2 1 1
The position of object 1(top-to-bottom):3
The position of object 1(tottom-to-top):7
The new vector(resized the vector)is:
[one,four,3.9,1]
E:java01>
从例1中运行的结果中可以清楚地了解上面各种方法的作用,另外还有几点需解释。
(1)类Vector定义了方法
public final int size()
此方法用于获取向量元素的个数。它的返回值是向是中实际存在的元素个数,而非向量容量。可以调用方法capactly()来获取容量值。
方法:
public final synchronized void setsize(int newsize)
此方法用来定义向量大小。若向量对象现有成员个数已超过了newsize的值,则超过部分的多余元素会丢失。
(2)程序中定义了Enumeration类的一个对象
Enumeration是java.util中的一个接口类,在Enumeration中封装了有关枚举数据集合的方法。
在Enumeration中提供了方法hawMoreElement()来判断集合中是否还有其它元素和方法nextElement()来获取下一个元素。利用这两个方法可以依次获得集合中元素。
Vector中提供方法:
public final synchronized Enumeration elements()
此方法将向量对象对应到一个枚举类型。java.util包中的其它类中也大都有这类方法,以便于用户获取对应的枚举类型。
详细说明/vectorvector 是同一种类型的对象的集合,每个对象都有一个对应的整数索引值 。
和 string 对象一样,标准库将负责管理与存储元素相关的内存。我们把 vector称为容器,是因为它可以包含其他对象,能够存放任意类型的 动态数组,增加和压缩数据。一个容器中的所有对象都必须是同一种类型的 。
vector 是一个类模板(class template)。使用模板可以编写一个类定义或函数定义,而用于多个不同的数据类型。因此,我们可以定义保存 string 对象的 vector,或保存 int 值的 vector,又或是保存自定义的类类型对象(如Sales_items 对象)的 vector。vector 不是一种数据类型,而只是一个类模板,可用来定义任意多种数据类型。vector 类型的每一种都指定了其保存元素的类型 。
为了可以使用vector,必须在你的头文件中包含下面的代码:
#include <vector>
vector属于 std命名 域的,因此需要通过命名限定,如下完成你的代码:
using std::vector;
vector<int> vInts;
或者连在一起,使用全名:
std::vector<int> vInts;
建议在代码量不大,并且使用的 命名空间不多的情况下,使用全局的命名域方式: using namespace std;
函数
表述
c.assign(beg,end) c.assign(n,elem)
将(beg; end)区间中的数据赋值给c。将n个elem的拷贝赋值给c。
传回索引idx所指的数据,如果idx越界,抛出out_of_range。
c.back()
传回较后一个数据,不检查这个数据是否存在。
c.begin()
传回 迭代器中的*数据地址。
c.capacity()
返回容器当前已分配的容量。
c.clear()
移除容器中所有数据。
c.empty()
判断容器是否为空。
c.end() //指向 迭代器中末端元素的下一个,指向一个不存在元素。
c.erase(pos)// 删除pos位置的数据,传回下一个数据的位置。
c.erase(beg,end)
删除[beg,end)区间的数据,传回下一个数据的位置。
c.front()
传回*数据。
get_allocator
使用 构造函数返回一个拷贝。
c.insert(pos,elem)//在pos位置插入一个elem拷贝,传回新数据位置
c.insert(pos,n,elem)//在pos位置插入n个elem数据,无返回值
c.insert(pos,beg,end)//在pos位置插入在[beg,end)区间的数据。无返回值
c.max_size()
返回容器中*数据的数量。
c.pop_back()
删除较后一个数据。
c. push_back(elem)
在尾部加入一个数据。
c.rbegin()
传回一个逆向队列的*数据。
c.rend()
传回一个逆向队列的较后一个数据的下一个位置。
c.resize(num)
重新指定队列的长度。
c.reserve()
保留适当的容量。
c.size()
返回容器中实际数据的个数。
c1.swap(c2)//将c1和c2元素互换
swap(c1,c2)//同上操作。
vector<Elem> //创建一个空的vector
vector<Elem> c1(c2)//复制一个vector
vector <Elem> c(n)//创建一个vector,含有n个数据,数据均已缺省构造产生
vector <Elem> c(n,elem)//创建一个含有n个elem拷贝的vector
vector <Elem> c(beg,end)//创建一个以(beg;end)为区间的vector
c.~ vector operator[] 返回容器中指定位置的一个引用。 创建一个vector vector容器提供了多种创建方法,下面介绍几种常用的。 创建一个Widget类型的空的vector对象: vector<Widget> vWidgets; 创建一个包含500个Widget类型数据的vector: vector<Widget> vWidgets(500); 创建一个包含500个Widget类型数据的vector,并且都初始化为0: vector<Widget> vWidgets(500,Widget(0)); 创建一个Widget的拷贝: vector<Widget> vWidgetsFromAnother(vWidgets); 向vector添加一个数据 vector添加数据的缺省方法是 push_back()。 push_back()函数表示将数据添加到vector的尾部,并按需要来分配内存。例如: 向vector<Widget>;中添加10个数据,需要如下编写代码: for(int i= 0;i<10; i++) { vWidgets. push_back(Widget(i)); } 获取vector中指定位置的数据 vector里面的数据是动态分配的,使用 push_back()的一系列分配空间常常决定于文件或一些数据源。 如果想知道vector是否为空,可以使用empty(),空返回true,否则返回false。获取vector的大小,可以使用size()。例如,如果想获取一个vector v的大小,但不知道它是否为空,或者已经包含了数据,如果为空时想设置为 -1,你可以使用下面的代码实现: int nSize = v.empty() ? -1 : static_cast<int>(v.size()); 访问vector中的数据 使用两种方法来访问vector。 1、 vector::at() 2、 vector::operator[] operator[]主要是为了与C语言进行兼容。它可以像C语言 数组一样操作。但at()是我们的*,因为at()进行了边界检查,如果访问超过了vector的范围,将抛出一个例外。由于operator[]容易造成一些错误,所以我们很少用它. 删除vector中的数据 vector能够非常容易地添加数据,也能很方便地取出数据,同样vector提供了erase(),pop_back(),clear()来删除数据,当删除数据时,应该知道要删除尾部的数据,或者是删除所有数据,还是个别的数据。 remove()算法 如果要使用remove,需要在头文件中包含如下代码: #include <algorithm> remove有三个参数: 1、 iterator _First:指向*数据的迭代 指针。 2、 iterator _Last:指向较后一个数据的迭代 指针。 3、 predicate _Pred:一个可以对 迭代操作的条件函数。 条件函数 条件函数是一个 按照用户定义的条件返回是或否的结果,是最基本的 函数指针,或是一个 函数对象。这个 函数对象需要支持所有的 函数调用操作, 重载operator()()操作。remove是通过unary_function继承下来的,允许传递数据作为条件。 例如,假如想从一个vector<CString>;中删除匹配的数据,如果字串中包含了一个值,从这个值开始,从这个值结束。首先应该建立一个 数据结构来包含这些数据,类似代码如下: #include <functional> enum findmodes { FM_INVALID = 0, FM_IS, FM_STARTSWITH, FM_ENDSWITH, FM_CONTAINS }; typedef struct tagFindStr { UINT iMode; CString szMatchStr; } FindStr; typedef FindStr* LPFINDSTR; 然后处理条件判断: class FindMatchingString : public std::unary_function<CString,bool> { public: FindMatchingString(const LPFINDSTR lpFS) : m_lpFS(lpFS) { } bool operator()(CString& szStringToCompare) const { bool retVal = false; switch (m_lpFS->iMode) { case FM_IS: { retVal = (szStringToCompare == m_lpFDD->szMatchStr); break; } case FM_STARTSWITH: { retVal = (szStringToCompare.Left(m_lpFDD->szMatchStr.GetLength()) == m_lpFDD->szWindowTitle); break; } case FM_ENDSWITH: { retVal = (szStringToCompare.Right(m_lpFDD->szMatchStr.GetLength()) == m_lpFDD->szMatchStr); break; } case FM_CONTAINS: { retVal = (szStringToCompare.Find(m_lpFDD->szMatchStr) != -1); break; } } return retVal; } private: LPFINDSTR m_lpFS; }; 通过这个操作你可以从vector中有效地删除数据: FindStr fs; fs.iMode = FM_CONTAINS; fs.szMatchStr = szRemove; vs.erase(std::remove_if(vs.begin(),vs.end(),FindMatchingString(&fs)),vs.end()); Remove(),remove等所有的移出操作都是建立在一个迭代范围上的,不能操作容器中的数据。所以在使用remove,实际上操作的时容器里数据的上面的。 看到remove实际上是根据条件对 迭代地址进行了修改,在数据的后面存在一些残余的数据,那些需要删除的数据。剩下的数据的位置可能不是原来的数据,但他们是不知道的。 调用erase()来删除那些残余的数据。注意上面例子中通过erase()删除remove的结果和vs.enc()范围的数据。 常见错误: no matching function for call to ‘std::vector,一般由定义的类型与存入的 类型不匹配引起。