java 容器排序_Java攻略第四章 容器类、排序

前面就是Java小世界的出口,是不是心中涌起莫名的冲动,想要一步跳出门去?这种心情可以理解,因为你还没有遇到真正的怪物。喂,不要急!在你即将跳出门去的刹那,最好还是看一下这个小东西!

可不要小看它!它在Java世界内扮演了重要角色,这就是容器类。首先,容器类是一个统称,它包含了许多实用类。它们是真正的“类”如其名,显而易见的功能是包含其它Java元素。当然,容器功能只是它们的基本属性,你要睁大眼睛,仔细研究它们附加的魔法属性。如果能熟练使用这些附加的属性,那我就不再阻拦你,你大可以飞出门去,即使以后可能跌个头破血流,绝保不会有性命之虞。

嗯,等我把它们全部捡出来。它们一般在java.util包里。先看Collection,它只是一个接口类,定义了容器类的基本属性。下面再来看看这些:Array、List、Map和Set。Array,即数组,并不是一个Java类,就是说,你不会找到叫Array的类,但它确实存在于Java世界内。数组的特色就是:访问指定索引元素的速度较快,但插入和删除指定元素就比较费劲,而且它是定长的。如果你想使用它,可以这样声明:数据类型[] 数组变量名称。例如你想要一个int类型的数组,那你只要这样呼喊:

int[] iArray;

喊完后,JVM就知道你需要一个int类型的,名字叫“iArray”的数组。然后你需要再喊出你期望数组容器有多大,就像这样:

iArray = new int[6];

好了,你现在有了一个可以装下6个int元素的数组容器。你可以存放,也可以取出int元素:

iArray[0] = 5;

int temp = iArray[5];

对于数组来说,要注意的是:JVM是根据索引来访问数组容器内的元素,并且索引是从0开始编号的。就拿刚才我们创建的数组容器,访问第六个元素的喊法是这样的:

iArray[5];

并不存在iArray[6]这个元素。如果你不小心喊出了iArray[6],JVM会因为你的贪婪而生气的。

接下来我们来看看List。List有许多种类。比较常见的有ArrayList、LinkedList、Stack、Vector。ArrayList、LinkedList、Stack、Vector虽然同为List类型容器,但各有各的特殊属性。比如ArrayList,它其实是数组外面粘贴了一些List枝叶,所以它像数组一样,访问指定索引元素的速度较快,但插入和删除指定元素就比较费劲。Vector具有同步属性,不需额外步骤,就支持并发访问。LinkedList具有链表的属性,一般来说它和ArrayList属性相反,它的插入和删除速度较快,但访问特定索引元素的速度较慢。Stack,就如它的名字,它具有栈的属性,提供在一端压入元素、弹出元素的功能。所有List类型的容器和数组比起来,最显著的区别是:List是变长的。你没有必要告诉JVM你需要多大尺寸的List,JVM会尽量满足你的收集欲望。不过你要格外小心,如果一不小心撑坏了JVM的肚皮,遭受打击的可不是JVM,而是你!

如果我们需要一个List容器,我们可以这样呼喊:List 容器名称。的例如:

List appleList;

如果你希望获取一个特定类型的List,你要指明它具体的类型,例如:

ArrayList appleList;

此时JVM会收到你的请求,但JVM并没有准备好容器,你要接着呼喊:

appleList = new

ArrayList();

这样JVM会准备好一个ArrayList类型的容器。然后你可以直接使用容器自带的add、remove等魔法向List容器内插入、删除元素,也可以使用get(int index)魔法获取指定索引的元素。

现在轮到Map容器了。Map同样也有许多种类。常见的有HashMap、Hashtable、LinkedHashMap和TreeMap。它们共同的属性是提供Key-Value映射。你可以提供一个Key,获取对应的Value。要说不同的属性,HashMap、Hashtable是Map的哈希表版本,这个决定了HashMap、Hashtable容器的容量是虚高的,也就是说,实际存放100个元素的容器,外表看上去像个容量超过100的胖子,具体胖到什么程度,要看容器的心情。如果预期存放的元素不多,这通常不是什么问题。LinkedHashMap同时具有哈希表和一些链表的属性,它在内部维护一个双向链表,链表内包含所有存放的元素。通过特殊的构造方法来创建这种类型的Map,该Map内链表的链接顺序就是最后访问其元素的顺序,即从近期访问最少到近期访问最多的顺序(访问顺序)。所以这种Map很适合构建 LRU 缓存。TreeMap呢,它具有红黑树的属性,所以TreeMap内的元素都是有序排列的,排序依据是Key值,或者使用指定的比较器Comparator决定,而且它的容量不是虚高的。

如果我们需要Map容器,我们可以这样呼喊:Map 容器名称。例如:

Map appleMap;

如果你希望获取一个特定类型的Map,你要指明它具体的类型,例如:

HashMap appleList;

此时JVM会收到你的请求,但JVM并没有准备好容器,你要接着呼喊:

appleMap = new

HashMap();

然后我们可以存放元素,

appleMap.put(“red”,redApple);

也可以取出元素,

appleMap.get(“red”);

甚至我们可以先看看容器内是否有指定的元素:

appleMap.containsKey(“red”);

最后是Set。和Map相似,可以把Set看作是退化为List的Map,或者是Key与Value相同的Map。它的常见类型有HashSet、LinkedHashSet、TreeSet。它们之间的区别可以参考Map。我一直没怎么用过Set类型容器,总是使用Map容器来模仿Set容器。Set容器在这种情况下比较实用:希望维护一个没有重复元素的List。

好了,常见的容器都挑拣出来了。对于容器来说,比较常见的操作就是遍历其中所有元素。要完成这项魔法,我们可以利用容器的Iterator属性。比如对于刚才的appleList,我们可以这样遍历其中元素:

for(Iterator iter =

appleList.iterator();iter.hasNext();){

Object apple =

iter.next();

//处理 apple

}

其实对于Array、List和Set来说,你可以这样遍历:

for(Apple apple :

appleList){

//处理 apple

}

Map是比较特殊的容器,它的遍历是通过遍历其keySet,然后由key获取Value这种方式实现,例如我们的appleMap:

for(Iterator iter =

appleMap.keySet().iterator();iter.hasNext();){

Object key =

iter.next();

Object apple =

appleMap.get(key);

//处理 apple

}

如果觉得这样有些绕弯,可以这样做:

for(Iterator iter =

appleMap.entrySet().iterator();iter.hasNext();){

Map.Entry entry =

(Map.Entry)iter.next();

Object key =

entry.getKey();

Object apple =

entry.getValue();

//处理 apple

}

对于遍历来说,我们需要记住的是,遍历一般是不保证顺序的,即前后两次遍历容器内的元素,很可能是以不同的顺序遍历。但LinkedHashMap、TreeMap、LinkedHashSet、TreeSet是保证遍历顺序的。对于Array和List来说,你完全可以用指定索引的方式,强制遍历顺序。例如:

for(int i =0; i<

appleList.size();i++){

Object apple =

appleList.get(i);

//处理 apple

}

有了容器,我们可以方便的存放元素。加入我们希望对容器内的元素排序该怎么办呢?不用急,Java世界内已经存在这样的魔法。我们可以用java.util包内的Arrays对数组进行排序,也可以使用Collections对List进行排序。同样,Map的keySet是Set类型容器,values是Collection类型容器,都可以转为List类型容器,当然可以用Collections魔法对其keySet和values排序。最后一点,说到排序,总是有个排序的规则吧。如果我们想指定排序规则该怎么办呢?这些都不用担心,Arrays和Collections内已经有对应的魔法,其中的关键是:我们需要提供排序规则实例,即Comparaor类型的元素。比如我们刚才创建的appleList,假定其中保存的是我们自定义的Apple类型对象,这个对象内有一个新鲜度属性:life,如果我们想要按照Apple的新鲜度对appleList内的所有Apple元素排序,那么我们先实现一个比较器对象:

class AppleComparator implements

Comparator{

public int compare(Apple appleA, Apple appleB) {

int cp = 0; //新鲜度一样

if(appleA.getLife>appleB.getLife){

cp = 1; //appleA新鲜

}

if(appleA.getLife>appleB.getLife){

cp = -1; //appleB新鲜

}

return cp;

}

}

然后我们使用Collections内的魔法:

Collections.sort(appleList,new

AppleComparator());

这样AppleList内元素就是按新鲜度排序好的。

关于容器的奥妙就讲这么多吧,这只是其中很少的部分,剩下的就需要你自己去发掘了。另外,对于上述涉及的容器,一般来说不适合并发访问。如果希望并发访问容器及容器内元素,请到java.util.concurrent包内找对应类型的并发版本容器。

好了,现在你可以跳出这个大门了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值