Java集合

集合是java常要使用的对象。本文对其中重要知识做个总结。

1. Iterator

迭代器是种设计模式,可以屏蔽各种集合的差异。使用时一要注意 它的remove()方法:每次使用它之前必须先调用 next(),方法,因为remove()删除的正是上次next方法返回的元素。二要注意迭代过程中不能修改Collection的元素。类似的,使用foreach迭代时也不能修改集合元素。

2. Set集合

HashSet是set接口的典型实现,有如下特点 :

不能保证元素的排列顺序;不是同步的(线程不安全);元素值可以是null。

在向HashSet集合存入一个元素时,会调用该对象的hashCode()方法来决定HashSet里存储位置。如果两个元素的equals()方法比较返回true,但是hashCode()返回不等,则会存储在不同的位置。简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals()方法比较相等,且hashCode()返回值相同。

因此,如果要把某个自定义类对象保存到HashSet集合,需重写equals()方法和hashCode()方法,并尽量保证两个对象equals()方法返回true时hashCode()返回也是相等。

从上面的分析不难得出结论,假设一个类的hashCode方法和equals方法和它的一个属性值唯一相关,如果修改了对象属性值就可以出现相同对象的情况;但因为HashSet已经把他们存在不同地方,所以这会引起混乱。因此建议不要添加可改变的对象。下面给个实例:

class R{
	int count;
	public R(int count)
	{
		this.count = count ;
	}
	public String toString()
	{
		return "R[count:"+count+"]";

	}
	public boolean equals(Object obj)
	{
		if(this == obj) return true;
		if(obj != null && obj.getClass() == R.class)
		{
			R r = (R)obj;
			if(r.count == this.count)
			{
				return true;
			}
		}
		return false;
	}
	public int hashCode()
	{
		return this.count;
	}
}

public class SetTest{
	public static void main(String[] args)
	{
		HashSet hs = new HashSet();
		hs.add(new R(5));
	        hs.add(new R(-3));
		hs.add(new R(9));
		hs.add(new R(-2));
		System.out.println(hs);
		Iterator it = hs.iterator();
		R first =(R)it.next();
		first.count = -3;
		System.out.println(hs);
		hs.remove(new R(-3));
		System.out.println(hs);
		System.out.println("hs contains -3 ?"+ hs.contains(new R(-3)));
		System.out.println("hs contains 5 ?"+ hs.contains(new R(5)));

	}
}

代码首先添加四个不同元素,实际顺序是 5,9,-3,-2。修改后是-3,9,-3,2,也就是出现了相同元素。执行remove时,利用它的hashCode找到存储位置,也就是第三个元素被删除。成了 -3,9,2。最后发现 hs.contains(new R(-3))是false,原因也是通过找到存储位置再比较,此时-3存储的位置也不是new R(-3)对象,所以返回false。同理,最后一句也是返回false.


Set的其他实现还有TreeSet、SortSet等,一般我们是考虑使用HashSet的,因为TreeSet需要额外的红黑树来维护元素次序,它的性能不及HashSet。只有需要一个保持排序的Set,才推荐使用TreeSet。(TreeSet判断相等时equals方法和compare方法,这里不展开说明。)

关于上面的线程不安全问题,Collections工具类封装了较好的实现,只需如下代码:

HashSet hs = Collections.synchronizedHaset(new HashSet());

3. List集合

List集合判断相同的条件是equals方法。

考虑下面的代码:

// 类A的equals方法始终返回true
List book = new ArrayList();
book.add(new Stirng("A"));
book.add(new Stirng("B"));
book.add(new Stirng("C"));
book.remove(new A());

上面的remove方法是可以成功执行的,因为内部的机制是先调用new A()对象的equals方法依次和集合元素比较,如果返回true,则成功删除。

List的两种典型实现是ArrayList和Vector,其中Vector是个古老的集合,有很多功能重复的方法,一般推荐使用ArrayList。另一方面,由于Vector是线程安全的,所以Vector的性能比ArrayList差。实际上,使用上面提供的Collections工具类的方法可以解决这一问题。

这里特别指出一个常用的生成List的方法,ArrayList.asList(Object...a),要牢记这个List集合既不是ArrayList实现类,也不是Vector的实现类,而是Arrays的内部类ArrayList的实例,它是个固定长度的集合,不可增删。


4. Map集合

熟悉JDKAPI的读者会发现Map和Set的API有惊人的相似,这是因为Map提供了一个Entry内部类来封装key-value,而计算Entry的存储时只考虑Entry封装的key。从源码来看,如果把所有的value都为null就实现类Set集合。

典型实现有HashMap和Hashtable,,推荐HashMap。因为Hashtable是个古老的类,从它不符合规范的命令就可以看出。除此之外,它们的其他典型区别有:Hashtable线程安全;HashMap允许null为key,value。

类似HashSet,HashMap判断两个key相等的依据是两个key的equals()方法比较true,hashCode返回值相等。


5. Collections工具类

Collections是用以操作Set,List,Map的工具类。提供了像static void reverse(List list),static void sort(List list)等实用方法。

上面也提及了Collections对同步的控制,语法很简单,即使用 synchronizedXxx()方法。

上面也提及推荐在HashSet、HashMap里尽量使用不可变对象。Collections也提供相应的保证。

一种方法是 emptyXxx()方法,返回一个空的、不可变集合对象;二是使用 singletonXxx();三是使用 unmodifiableXxx()。

List list = Collections.emptyList();
Set  set = Collections.singleton("A");

6. 

最后谈一下古老的接口Enumeration,在很多代码里可能有它的踪影,因此读者会觉得它很神秘。

它只有两个方法  boolean hasMoreElements(),Object nextElement()。

我们是不推荐使用它的,因为Interator能完成它的所有功能,且性能更好。Java 新版本保留它仅是为了兼顾以前的程序。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值