MyException - 我的异常网
当前位置:我的异常网» Java相关 » 器皿类的入门知识

器皿类的入门知识

www.MyException.Cn  网友分享于:2013-08-09  浏览:0次
容器类的入门知识

java容器类的用途就是用来保存多个对象,主要可以分为两类:

1)Collection:用来存储多个独立的元素(对象),继承它的子接口有三个:1)List必须按照插入的顺序保存元素2)Set不能存储重复的元素3)Queue按照元素的排队规则来决定元素的取出顺序(通常与元素的插入顺序有关)

2)Map:用来存储多个成对的键值对对象,可以通过键(对象)来查找对应的值(对象),其中List接口的实现类ArrayList可以通过数字(下标)来查找值,这在某种意义上有点类似Map中将键值用数字来与值关联起来

List


实现List接口的集合类对象可以存放多个重复的元素,List接口在Collection的基础上增加了大量的功能,使得我们能够在集合的中间插入或删除元素,主要的实现类有以下两种

  • ArrayList:该集合类随机访问元素的效率较高,但在中间插入和移除元素的效率较低
  • LinkedList:该集合在中间插入和移除元素的效率较高,但随机访问元素的效率较低
int length = 100000;
Random random = new Random();
List<Integer> array = new ArrayList<>();
List<Integer> linked = new LinkedList<>();
for (int i = 0; i < length; i++) {
    array.add(i);
    linked.add(i);
}
Long time1 = System.currentTimeMillis();
for (int i = 0; i < length; i++)
    array.get(random.nextInt(length));
Long time2 = System.currentTimeMillis();
System.out.println("ArrayList的随机访问元素的时间:" + (time2 - time1) + "ms");
Long time3 = System.currentTimeMillis();
for (int i = 0; i < length; i++)
    linked.get(random.nextInt(length));
Long time4 = System.currentTimeMillis();
System.out.println("LinkedList随机访问元素的时间:" + (time4 - time3) + "ms");
Long time5 = System.currentTimeMillis();
while (!array.isEmpty())
    array.remove(0);
Long time6 = System.currentTimeMillis();
System.out.println("ArrayList移除对象的时间:" + (time6 - time5) + "ms");
Long time7 = System.currentTimeMillis();
while (!linked.isEmpty())
    linked.remove(0);
Long time8 = System.currentTimeMillis();
System.out.println("LinkedList移除对象的时间:" + (time8 - time7) + "ms");
/** output
 * ArrayList的随机访问元素的时间:14ms
 * LinkedList随机访问元素的时间:15600ms
 * ArrayList移除对象的时间:1098ms
 * LinkedList移除对象的时间:9ms
 */

1)从输出的前两行可以看出ArrayList的随机访问元素的效率明显高于LinkedList,ArrayList实际上是通过数组来存储对象,所以我们能够通过下标很快的查找到对应的元素,而LinkedList是链表式的存储结构,某个元素含有下一个与上一个元素的地址,而且访问元素的唯一入口是指向集合的第一个和最后一个元素的地址,例如我们若想访问第3个元素,就得通过第一个元素找到第二个元素,再通过第二个元素找到第三个元素,这就极大的降低了访问的效率,访问之前会先判断要访问的元素离起始元素的位置近还是结尾元素的位置近,再从离的较近的位置开始逐一访问,因此访问集合中间元素的效率是最低的

2)从输出的后两行可以看出ArrayList移除起始元素的效率明显低于LinkedList,这里我没有选择移除中间元素是因为移除中间元素必须要获取到这个元素,从1)中可以看出   LinkedList的获取中间元素的需要大量的时间,这会影响最终移除元素的时间,所以我选择移除访问时间相差不大的第一个元素,ArrayList移除第一个元素时必须将后面的每一个元素往前移动一个单位,这就需要大量的操作,而LinkedList只需将入口访问元素的地址指向第二个元素即可,其它元素不需要任何的改变

 Set


Set具有与Collection相同的接口,即未在Collection的基础上增加额外的功能,Set集合中不能存放重复的元素,判断元素是否重复是通过调用元素的equals方法来于集合中的元素进行比较,Set中元素的存储位置是通过元素的值来确定的。Set接口的实现类有三个,如下:

  • HashSet:为了提高查询效率,该集合中的元素排序使用的散列函数,使用的时候会发现元素的输出顺序是没有任何规律的
  • TreeSet:将元素存储在红-黑树数据结构中,若想对输出结果进行排序可以使用该函数代替HashSet(大多数情况无需考虑元素的顺序所以HashSet的使用率最高)
  • LinkedHashSet:为了提高查询效率也使用的散列函数,但是看起来它使用了链表来维护元素的插入顺序
int size = 10000;
Random random = new Random(47);
Set<Integer> hash = new HashSet<>();
System.out.print("插入的顺序 = [");
for (int i = 0; i < size; i++) {
    int num = random.nextInt(10) + 10;
    boolean flag = hash.add(num);
    if (flag)
        System.out.print(num + ", ");
}
System.out.println("]");
System.out.println("HashSet = " + hash);
random = new Random(47);
Set<Integer> tree = new TreeSet<>();
for (int i = 0; i < size; i++)
    tree.add(random.nextInt(10) + 10);
System.out.println("TreeSet = " + tree);
random = new Random(47);
Set<Integer> linkedHash = new LinkedHashSet<>();
for (int i = 0; i < size; i++)
    linkedHash.add(random.nextInt(10) + 10);
System.out.println("LinkedHashSet = " + linkedHash);
/** output
 * 插入的顺序 = [18, 15, 13, 11, 19, 10, 12, 17, 16, 14, ]
 * HashSet = [16, 17, 18, 19, 10, 11, 12, 13, 14, 15]
 * TreeSet = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
 * LinkedHashSet = [18, 15, 13, 11, 19, 10, 12, 17, 16, 14]
 */

以上代码中我选择了插入10-19的元素是因为jdk8中散列函数可能与jdk7中有所不同,若使用0-9的数字HashSet输出结果将与TreeSet一样好像对元素进行了排序,其中我为random重新赋值了两次是为了使三个集合的插入元素的顺序保持一致。从第二行的输出中可以看到元素的输出顺序与插入顺序无关,看起来毫无规则;从第三行的输出可以看出TreeSet集合中的元素存储在红-黑树数据结构中;从第三行的输出能看出LinkedHashSet中元素的存储与插入顺序有关

Queue


Queue(队列)是一个典型的先进先出的容器。即从容器的一端插入元素,从另一端获取元素,正是因为这个特性队列是一个可靠的传输对象的途径。队列在并发编程中非常重要。它的主要实现类有以下两种:

  • LinkedList:不但实现了List接口还实现了Queue接口,所以该集合拥有许多ArrayList没有的功能,即一些对集合中首尾元素操作的方法
  • PriorityQueue :即优先级队列,当插入元素时,会对这个元素进行排序,可以通过提供自己的比较器来对元素进行排序,每次获取的元素都是优先级最高的(最前面的)
Random random = new Random(47);
System.out.print("元素插入的顺序 = [");
Queue<Integer> linkedList = new LinkedList<>();
for (int i = 0; i < 10; i++) {
    int num = random.nextInt(10);
    linkedList.offer(num);
    System.out.print(num + ", ");
}
System.out.println("]");
System.out.println("插入元素后的LinkedList = " + linkedList);
for (int i = 0; i < 10; i++)
    linkedList.poll();
System.out.println("弹出元素后的LinkedList = " + linkedList);
random = new Random(47);
Queue<Integer> priority = new PriorityQueue<>();
for (int i = 0; i < 10; i++)
    priority.offer(random.nextInt(10));
System.out.println("插入元素后的PriorityQueue = " + priority);
System.out.print("PriorityQueue中元素的弹出顺序 = [");
for (int i = 0; i < 10; i++)
    System.out.print(priority.poll() + ", ");
System.out.println("]");
/** output
 * 元素插入的顺序 = [8, 5, 3, 1, 1, 9, 8, 0, 2, 7, ]
 * 插入元素后的LinkedList = [8, 5, 3, 1, 1, 9, 8, 0, 2, 7]
 * 弹出元素后的LinkedList = []
 * 插入元素后的PriorityQueue = [0, 1, 5, 1, 3, 9, 8, 8, 2, 7]
 * PriorityQueue中元素的弹出顺序 = [0, 1, 1, 2, 3, 5, 7, 8, 8, 9, ]
 */

 从上面的代码中可以看出LinkedList相比与ArrayList多了offer与poll方法对集合的首尾元素进行操作,LinkedList还有许多特有的方法这里就不列举出来了。从元素的插入顺序与插入元素后的PriorityQueue中可以看出元素插入的时候对元素进行了排序,而且在元素弹出的时候又对队列中的元素进行了排序

Map


将对象映射到其它的对象可以解决一些比较难实现的功能,Map中存放的就是以两个对象组成的键(key)值(value)对,Map中的key是不能重复的这就保证了每个键值对都是不同的,但是value值是可以相同的,我们可以通过key快速的获取value。Map的主要实现类有以下两种:

  • HashMap:该Map中的元素通过key的散列码进行排序,可以存放key值为null的键值对,但不能有多个
  • LinkedHashMap:该类在日常的编码中很少用到
Random random = new Random(47);
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < 10000; i++) {
    int num = random.nextInt(20);
    Integer value = map.get(num);
    map.put(num, value == null ? 1 : value + 1);
}
System.out.println(map);
/** output
 * {0=481, 1=502, 2=489, 3=508, 4=481, 5=503, 6=519, 7=471, 8=468, 9=549, 10=513,
 * 11=531, 12=521, 13=506, 14=477, 15=497, 16=533, 17=509, 18=478, 19=464}
 */

这段代码实现了对随机产生的10000个0-19数字进行统计各个数出现的次数,若我们想通过集合实现这个功能则需要将这10000个随机数进行多次遍历来逐一统计每个数出现的次数。这不仅增加了代码实现的难度,而且实现后的效率将会明显低于Map

最后附上一张java容器的简图。这里只包含了你在一般情况下会使用的接口和类,忽略了所有抽象类,另外还有一些过时的容器类,例如Vector、HashTable和Stack也没有出现在下面的图中

实现框表示类(加粗的是常用的);虚线框表示接口;带有空心箭头的虚线表示实现了某个接口;带有空心箭头的实线表示继承某个类;带有实心箭头的虚线表示可以产生它

 

文章评论

5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
程序员的鄙视链
程序员的鄙视链
程序员和编码员之间的区别
程序员和编码员之间的区别
程序员应该关注的一些事儿
程序员应该关注的一些事儿
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
老程序员的下场
老程序员的下场
每天工作4小时的程序员
每天工作4小时的程序员
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
代码女神横空出世
代码女神横空出世
如何成为一名黑客
如何成为一名黑客
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
为什么程序员都是夜猫子
为什么程序员都是夜猫子
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
漫画:程序员的工作
漫画:程序员的工作
我的丈夫是个程序员
我的丈夫是个程序员
10个调试和排错的小建议
10个调试和排错的小建议
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
程序员必看的十大电影
程序员必看的十大电影
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
一个程序员的时间管理
一个程序员的时间管理
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
我是如何打败拖延症的
我是如何打败拖延症的
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
编程语言是女人
编程语言是女人
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
那些争议最大的编程观点
那些争议最大的编程观点
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
中美印日四国程序员比较
中美印日四国程序员比较
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
 程序员的样子
程序员的样子
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有