当前位置:首页 » Java基础教程 » Java集合类

Java集合类

Java集合类- Vector(矢量), BitSet(位集), Stack(堆栈), Hashtable(散列表)。

Java集合类

在写程序的时候并不是每次只使用一个对象, 更多的是对一组对象进行操作, 就需要知道如何组合这些对象, 还有在编码的时候我们有时并不知道到底有多少对象,它们需要进行动态的分配存放。

Java的集合类只能容纳对象句柄, 对于简单类型的数据存放, 只能通过数据来存放, 数组可以存放简单类型的数据也能存放对象。

Java提供了四种类型的集合类: Vector(矢量), BitSet(位集), Stack(堆栈), Hashtable(散列表)。

1.         矢量: 一组有序的元素, 可以通过index进行访问。

2.         位集: 其实就是由二进制位构成的Vector, 用来保存大量”开-关”信息, 它所占的空间比较小, 但是效率不是很高, 如果想高效率访问, 还不如用固定长度的数组。

3.         堆栈: 先入后出(LIFO)集合, java.util.Stack类其实就是从Vector继承下来的, 实现了pop, push方法。

4.         散列表: 由一组组“键--值”组成, 这里的键必须是Object类型。 通过Object的hashCode进行高效率的访问。

对于这些集合之间的关联关系见下图, 其中标色的部分为我们常用的类。

由上图可以看出, 基本接口有两个:

Collection: 所有的矢量集合类都从它继承下去的, 但并不直接从它继承下去的。 List与Set这两个接口直接继承了Collection, 他们的区别是List里面可以保存相同的对象句柄, 而Set里面的值是不重复的。 我们经常用的Vector与ArrayList就是从List继承下去的, 而HashSet是从Set继承的。

Map:散列表的接口, Hashtable与HashMap继承了这个接口。

下面给出常用集合类的常用方法。

/**

 * Vector 与 ArrayList的操作几乎是一样的

 * 常用的追加元素用add(), 删除元素用remove()

 * 取元素用get(), 遍历它可以循环用get()取. 或者

 * 先得到一个Iterator, 然后通过遍历Iterator的方法

 * 遍历Vector或ArrayList

 */

// 生成一个空的Vector

Vector vector = new Vector();

// 在最后追加一个元素。

vector.add("one");

vector.add("two");

// 在指定的地方设置一个值

vector.set(0, "new one");

// 移走一个元素或移走指定位置的元素

vector.remove(0);

// 用for循环遍历这个Vector

for (int i = 0; i < vector.size(); i++) {

String element = (String) vector.get(i); }

// 用枚举器(Enumeration)遍历它(只有Vector有,ArrayList没有)

Enumeration enu = vector.elements();

while (enu.hasMoreElements()) {

enu.nextElement();}

// 用反复器(Iterator)遍历它

Iterator it = vector.iterator();

while (it.hasNext()) {it.next();}

/**

 * Hashtable与HashMap的操作, 追加元素用put(不是add)

 * 删除元素用remove, 遍历可以用Iterator 既可以遍历

 * 它的key, 也可以是value

 */

// 生成一个空的Hashtable或HashMap

Hashtable hashtable = new Hashtable();

// 追加一个元素

hashtable.put("one", "one object value");

// 删除一个元素

hashtable.remove("one");

// 用Iterator遍历

Iterator keyIt = hashtable.keySet().iterator();

while (keyIt.hasNext()) {

Object keyName = keyIt.next();

String value = (String) hashtable.get(keyName); }

Iterator valueIt = hashtable.values().iterator();

while (valueIt.hasNext()) {

valueIt.next();}


// 用Enumeration遍历, 只有Hashtable有, HashMap没有.

Enumeration enu = hashtable.elements();

while (enu.hasMoreElements()) {

enu.nextElement();}


说明: Enumeration是老集合库中的接口, 而Iterator是新集合(1.2)中出现的, 而Vector与Hashtable也都是老集合中的类, 所以只有Vector与Hashtable可以用Enumeration。


Vector与ArrayList对比:

虽然在使用的时候好象这两个类没什么区别, 它们都是从List继承下来的, 拥有相同的方法, 但它们的内部还是有些不同的,

Ø         首先Vector在内部的一些方法作了线程同步(synchronized)。 同步的代价就是降低了执行效率, 但提高了安全性。而ArrayList则是线程不同步的, 可以多线程并发读写它。

Ø         内部数据增长率。 所有的这些矢量集合在内部都是用Object的数组进行存储和操作的。 所以也就明白了为什么它可以接受任何类型的Object, 但取出来的时候需要进行类型再造。 Vector与ArrayList具有自动伸缩的功能, 我们不用管它size多大, 我们都可以在它的后面追加元素。 Vector与ArrayList内部的数组增长率是不一样的, 当内部的数组不能容纳更多元素的时候, Vector会自动增长到原两倍大小, ArrayList会变为原一倍半大小, 而不是我们所想象的一个元素一个元素的增长。


Hashtable与HashMap对比:

Hashtable与HashMap都是从Map继承下来的, 方法几乎都一样, 它们内部有两个不同点:

Ø         与Vector和ArrayList一样, 它们在线程同步是不同的, Hashtable在内部做了线程同步, 而HashMap是线程不同步的。

Ø         HashMap的键与值都可以为null, 而Hashtable不可以, 如果你试图将一个null值放到Hashtable里面去, 会抛一个NullPointException的。


性能对比:

抛开不常用的集合不讲, 每种集合都应该有一个我们常用的集合类, 而在不同的场合下应该使用效率最高的一个。 一般来说我推荐尽量使用新的集合类, 除非不得已, 比如说需要用用了老集合类写的产品的程序。 也就是说尽量使用ArrayList与HashMap, 而少使用Vector与Hashtable。

Ø         在单线程中使用ArrayList与HashMap, 而在多线程中如果需要进行线程同步可以使用Vector与Hashtable, 但也可以用synchronized对ArrayList与HashMap进行同步, 不过同步后的ArrayList与HashMap是比Vector与Hashtable慢的。 不过我认为需要进行线程同步的地方并不多。 如果一个变量定义在方法内部同时只可能有一个线程对之进行操作, 就不必要进行同步, 如果定义在类的内部并且不是静态的, 属于实例变量, 而这个类并没有被多线程使用也就不必要同步。
一般自己写的程序很少会自己去另开线程的, 但在Web开发的时候, 如果用了Servlet, 则每个request都是一个线程, 也就是说每个Servlet都是在多线程环境下运行的, 如果Servlet中使用了全局静态的成员变量就得小心点儿, 如果需要同步就得在方法上加上synchronized修饰符, 如果允许多个线程操作它, 并且你知道不会有什么冲突问题就可以大胆的使用ArrayList与HashMap。 另外如果在多线程中有线程在对ArrayList或HashMap进行修改(结构上的修改), 而有一个线程在用Iterator进行读取操作, 这个时候就有可能会抛ConcurrentModificationException, 因为用Iterator的时候, 不允许原List的结构改变。但可以用get方法来取。


常用技巧:

1.         采用面向接口的编程技巧, 比如现在需要写一个共通函数,对矢量集合类诸如Vector,ArrayList,HashSet等等进行操作, 但我并不知道最终用户会具体传给我什么类型的类, 这个时候我们可以使用Collection接口, 从而使代码具有很大的灵活性。 代码示例如下:

/**

 * 将list里面的所有元素用sep连接起来,

 * list可以为Vector, ArrayList, HashSet等。

 */

public static String join(String sep, Collection list) {

   StringBuffer sb = new StringBuffer();

   Iterator iterator = list.iterator();

   while (iterator.hasNext()) {

          sb.append(iterator.next());

          if (iterator.hasNext()) { sb.append(sep); }

   }

   return sb.toString();

}


2.         利用Set进行Unique, 比如有一组对象(其中有对象是重复的), 但我们只对不同的对象感兴趣, 这个时候可以使用HashSet这个集合类, 然后可以通过覆盖Object的equals方法来选择自定义判断相等的rule。 缺省的是地址判断。 例:

class DataClass {

   private String code = null;

   private String name = null;


   public void setCode(String code) {this.code = code; }

   public String getCode() {return this.code; }

   public void setName(String name) {this.name = name; }

   public String getName() {return this.name; }

   public boolean equals(DataClass otherData) {

          if (otherData != null) {

                 if (this.getCode() != null&& this.getCode().equals(otherData.getCode()) {

                        return true;

                 }

          }

          return false;

   }}

DataClass data1 = new DataClass();

DataClass data2 = new DataClass();

data1.setCode("1");

data2.setCode("1");

HashSet singleSet = new HashSet();

singleSet.add(data1);

singleSet.add(data2);

结果singleSet里面只有data1, 因为data2.equals(data1), 所以data2并没有加进去。


3.         灵活的设计集合的存储方式, 以获得较高效的处理。 集合里面可以再嵌套集合, 例:在ArrayList里面存放HashMap, HashMap里面再嵌套HashMap。