java的集合
来源:互联网 发布:走势图制作软件 编辑:程序博客网 时间:2024/06/06 00:34
我们在前面学过Java数组,Java数组的长度是固定的,在同一个数组中只能存放相同的类型的数据。数组可以存放基本类型的数据,了可以存入对象引用的数据。
在创建数组时,必须明确指定数组的长度,数组一旦创建,其长度就不能被改变,在许多应用的场合,一组数据的数目是不固定的,比如一个单位的员工数目是变化的,有老的员工跳槽,也有新的员工进来。
为了使程序能方便地存储和操纵数目不固定的一组数据,JDK中提供了Java集合,所有Java集合类都位于java.util包中,与Java数组不同,Java集合不能存放基本数据类型数据,而只能存放对象的引用。
java集合类分为三种:
Set(集合):集合中对象不按特定的方式排序。并且没有重复对象,但它的有些实现类对集合中的对象按特定方式排序。
List(列表):集合中的对象按照索引位置排序,可以有重复对象,允许按照对象在集合中的索引位置检索对象,List和数组有些相似。
Map(映射):集合中的每一个元素包含一对键对象和值对象,集合中没有重复的键对象,值对象可以重复,它的有些实现类能对集合中的键对象进行排序。
Java的主要集合类的框架图:
Collection和Iterator接口:
在Collection接口中声明了适用于Java集合(只包括Set和List)通用方法。
Collection接口的方法
方法
描述
boolean add(Object o)
向集合中加入一个对象的引用
void clear()
删除中集合中所有对象,即不再对持有对象的引用
boolean contains(Object o)
判断在集合中是否含有特定对象的引用
boolean isEmpty()
判断集合是否为空
Iterator iterator()
返回一个Iterator对象,可用它来遍历集合中的元素
boolean remove(Object o)
从集合中删除一个对象的引用
int size()
返回集合中元素的数目
Object[] toArray()
返回一个数组,该数组包含集合中的所有元素
Set接口和List接口都继承了Collection接口,而Map接口有继承Collection接口,而继承了因此可以对Set对象和List对象调用以上方法,但是不能对Map对象调用以上方法
Collection接口的iterator()和toArray()方法都用于获得集合中的所有元素,前者返回一个Iterator对象,后者返回一个包含集合中所有元素的数组。
Iterator隐藏底层集合的数据结构,向客户程序提供了遍历各种类型的集合的统一接口中。Iterator接口中声明了如下方法:
l hasNext():判断集合中的元素是否遍历完毕,如果没有,就返回true.
l next():返回下一个元素。
l remove():从集合中删除上一个由next()方法返回的元素
注意:如果集合中的元素没有排序,Iterator遍历集合中元素的顺序是任意的,并不一定与向集合中加入元素的顺序一致的
Set(集)
Set是最简单一种集合,集合中的对象不按特定方式排序,并且没有重复对象。Set接口主要有两个实现类:HashSet和TreeSet。HashSet类按照哈希算法来存取集合中的对象,存取速度比较快。HashSet类还有一个子类LinkedHashSet类,它不仅实现了哈希算法,而且实现了链表数据结构,链表数据结构能提高插入和删除元素的性能。TreeSet类实现了SortedSet接口中,具有排序功能。
List(列表)
List的主要特征是其元素以线性方式存储,集合中允许存放重复对象。List接口主要的实现类包括:
l ArrayList-ArrayList代表长度可变的数组。允许对元素进行快速的随机访问,但是向ArrayList中插入与删除元素的速度较慢。
l LinkedList-在实现中采用链表数据结构。对顺序访问进行了优化,向List中插入和删除元素的速度较快,随机访问速度则相对较慢,随机访问是指检索位于特定索引位置元素。
Map(映射)
Map(映射)是一种把鍵对象和值对象进行映射的集合。它的每一个元素都包含一对键对象和值对象,而值对象仍可以是Map类型。依此类推,这样就形成了多级映射。向Map集合中加入元素时,必须提供一对键对象和值对象,从Map集合上检索元素只要给出键对象,就会返回对应的值对象。
实例1
CollectionAll.java
package collection;import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.LinkedHashMap;import java.util.LinkedHashSet;import java.util.LinkedList;import java.util.List;import java.util.Hashtable;import java.util.Map;import java.util.Set;import java.util.SortedMap;import java.util.SortedSet;import java.util.TreeMap;import java.util.TreeSet;public class CollectionAll { public static void main(String[] args) { List list1 = new LinkedList(); list1.add("我"); list1.add("是"); list1.add("谁"); list1.add("我"); traverse(list1); List list2 = new ArrayList(); list2.add("我"); list2.add("是"); list2.add("谁"); list2.add("我"); traverse(list2); Set set1 = new HashSet(); set1.add("我"); set1.add("是"); set1.add("谁"); set1.add("我"); traverse(set1); SortedSet set2 = new TreeSet(); set2.add("我"); set2.add("是"); set2.add("谁"); set2.add("我"); traverse(set2); LinkedHashSet set3 = new LinkedHashSet(); set3.add("我"); set3.add("是"); set3.add("谁"); set3.add("我"); traverse(set3); Map m1 = new HashMap(); m1.put("name01", "我"); m1.put("name02", "是"); m1.put("name03", "谁"); m1.put("name04", null); traverse(m1.keySet()); traverse(m1.values()); SortedMap m2 = new TreeMap(); m2.put("name01", "我"); m2.put("name02", "是"); m2.put("name03", "谁"); m2.put("name04", "我"); traverse(m2.keySet()); traverse(m2.values()); LinkedHashMap m3 = new LinkedHashMap(); m3.put("name01", "我"); m3.put("name02", "是"); m3.put("name03", "谁"); m3.put("name04", "我"); traverse(m3.keySet()); traverse(m3.values()); Hashtable numbers = new Hashtable(); numbers.put("name01", "我"); numbers.put("name02", "是"); numbers.put("name03", "谁"); numbers.put("name04", "我"); traverse(numbers.keySet()); traverse(numbers.values()); } static void traverse(Collection coll) { Iterator iter = coll.iterator(); while (iter.hasNext()) { String elem = (String) iter.next(); System.out.print(elem + " "); } System.out.println(); }}
一、集合框架中的各种实现类
HashSet类
HashSet类按照哈希算法一存取集中的对象,具有很好的存取和查找性能。当向集合中加入一个对象时,HashSet会调用对象的hashCode()方法来获得哈希码,然后根据这个哈希码进一步计算出对象在集合中的存放位置。
实例2 MyHashSet.java
package collection;import java.util.*; public class MyHashSet{ public static void main(String[] args) { HashSet set = new HashSet(6); Object[] values={"Tom","Mike","Jack","Mary","Linda","Jone"}; for(int i=0;i<values.length;i++) set.add(values[i]); //向集合中加入对象 set.remove("Mike"); //从集合中删除一个对象 System.out.println("size="+set.size()); Iterator iter=set.iterator(); //获得集合中的所有对象 while (iter.hasNext()) { String elem = (String) iter.next(); System.out.println(elem + " ");; } System.out.println(set.contains("Jack")); //打印true System.out.println(set.contains("Linda")); //打印true System.out.println(set.contains("Mike")); //打印false } }
TreeSet类
TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序,以下程序创建了一个TreeSet对象,然后向集合中加入4个Integer对象
实例3
TreeSetTest.java
package collection;import java.util.*;public class TreeSetTest {public static void main(String[] args) { Set set=new TreeSet(); set.add(new Integer(8)); set.add(new Integer(7)); set.add(new Integer(6)); set.add(new Integer(9)); Iterator it=set.iterator(); while(it.hasNext()){ System.out.println(it.next()+""); } }}
由此我们知道当TreeSet集合中加入一个对象时,会把它插入到有序的对象序列中。
ArrayList类
ArrayList-ArrayList代表长度可变的数组。允许对元素进行快速的随机访问,它允许所有元素,包括null。ArrayList是线程不同步的,向ArrayList中插入与删除元素的速度较慢
LinkedList类
LinkedList-实现了List接口,允许null元素,在实现中采用链表数据结构。对顺序访问进行了优化,向List中插入和删除元素的速度较快,随机访问速度则相对较慢,随机访问是指检索位于特定索引位置元素。
注意LinkedList没有同步方法。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(...));
实例4
StackL.java
package collection;import java.util.LinkedList;public class StackL { private LinkedList list = new LinkedList(); public void push(Object v) { list.addFirst(v); } public Object top() { return list.getFirst(); } public Object pop() { return list.removeFirst(); } public static void main(String[] args) { StackL stack = new StackL(); for (int i = 0; i < 10; i++) stack.push(new Integer(i)); System.out.println(stack.top()); System.out.println(stack.top()); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack.pop()); }}
ListIterator接口
List的listIterator()方法返回一个ListIterator对象,ListIterator接口继承了Iterator接口中,此外还提供了专门操纵列表的方法。
l add():向列表插入一个元素
l hasNext(): 判断列表中是否还有下一个元素
l hasPrevious(): 判断列表中是否还有上一个元素
l next(): 返回列表中的下一个元素
l previous(): 返回列表中的上一个元素
实例5
ListInserter.java
import java.util.*;public class ListInserter { /** 向List列表中按顺序插入一数据 */ public static void insert(List list,int data){ ListIterator it=list.listIterator(); while(it.hasNext()){ Integer in=(Integer)it.next(); if(data<=in.intValue()){ it.previous(); it.add(new Integer(data)); //插入元素 break; } } } public static void main(String args[]){ List list=new LinkedList(); //创建一个链接列表 list.add(new Integer(3)); list.add(new Integer(2)); list.add(new Integer(5)); list.add(new Integer(9)); Collections.sort(list);//为列表排序 insert(list,6); //向列表中插入一个元素 ListIterator it=list.listIterator(); while(it.hasNext()){ Integer elem = (Integer) it.next(); System.out.println(elem + " "); } }}
实例6 比较Java数组和各种List的性能
PerformanceTester..java
package collection;import java.util.*;public class PerformanceTester{ private static final int TIMES=100000; public static abstract class Tester{ private String operation; public Tester(String operation){this.operation=operation;} public abstract void test(List list); public String getOperation(){return operation;} } static Tester iterateTester=new Tester("iterate"){ public void test(List list){ //迭代操作 for(int i=0;i<10;i++){ Iterator it=list.iterator(); while(it.hasNext()){ it.next(); } } } }; static Tester getTester=new Tester("get"){ public void test(List list){ //随机访问操作 for(int i=0;i<list.size();i++) for(int j=0;j<10;j++) list.get(j); } }; static Tester insertTester=new Tester("insert"){ public void test(List list){ //插入操作 ListIterator it=list.listIterator(list.size()/2); //从列表的中间开始 for(int i=0;i<TIMES/2;i++) it.add("hello"); } }; static Tester removeTester=new Tester("remove"){ //执行删除操作的匿名类 public void test(List list){ //删除操作 ListIterator it=list.listIterator(); while(it.hasNext()){ it.next(); it.remove(); } } }; static public void testJavaArray(List list){ Tester[] testers={iterateTester,getTester}; test(testers,list); } static public void testList(List list){ Tester[] testers={insertTester,iterateTester,getTester,removeTester}; test(testers,list); } static public void test(Tester[] testers,List list){ for(int i=0;i<testers.length;i++){ System.out.print(testers[i].getOperation()+"操作:"); long t1=System.currentTimeMillis(); testers[i].test(list); long t2=System.currentTimeMillis(); System.out.print(t2-t1+" ms"); System.out.println(); } } public static void main(String args[]){ List list=null; //测试Java数组 System.out.println("----测试Java数组----"); String[] ss=new String[TIMES]; Arrays.fill(ss,"hello"); list=Arrays.asList(ss); testJavaArray(list); ss=new String[TIMES/2]; Collection col=Arrays.asList(ss); //测试Vector System.out.println("----测试Vector----"); list=new Vector(); list.addAll(col); testList(list); //测试LinkedList System.out.println("----测试LinkedList----"); list=new LinkedList(); list.addAll(col); testList(list); //测试ArrayList System.out.println("----测试ArrayList----"); list=new ArrayList(); list.addAll(col); testList(list); }}
从结果可以看出,对Java数组进行随机访问和迭代操作具有最快的速度;对LinkedList进行插入和删除具有最快的速度;对ArrayList进行随机访问也具有较快的速度,Vector类在各方面都没有突出的性能,属于历史集合类,已经不提倡使用它。
Map
Map(映射)是一种把鍵对象和值对象进行映射的集合。它的每一个元素都包含一对键对象和值对象,而值对象仍可以是Map类型。依此类推,这样就形成了多级映射。向Map集合中加入元素时,必须提供一对键对象和值对象,从Map集合上检索元素只要给出键对象,就会返回对应的值对象。
HashMap
HashMap类按照哈希算法一存取Map中的对象,允许存储空对象,而且允许键是空
实例7
Statistics.java
package collection;import java.util.HashMap;import java.util.Map;import java.util.Random; class Counter { int i = 1; public String toString() { return Integer.toString(i); }}public class Statistics { private static Random rand = new Random(); public static void main(String[] args) { Map hm = new HashMap(); for (int i = 0; i < 10000; i++) { // Produce a number between 0 and 20: Integer r = new Integer(rand.nextInt(20)); if (hm.containsKey(r)) ((Counter) hm.get(r)).i++; else hm.put(r, new Counter()); } System.out.println(hm); }}
Hashtable
Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。
实例8
HashTable.java
package collection;import java.util.Enumeration;import java.util.Hashtable;public class HashTable { public static void main(String args[]) { String names[] = { "张三", "李四", "王五", "赵六", "陈七", "孙九"}; float diameters[] = { 4800f, 12103.6f, 12756.3f, 6794f, 142984f, 120536f }; Hashtable hash = new Hashtable(); for (int i = 0, n = names.length; i < n; i++) { hash.put(names[i], new Float(diameters[i])); } Enumeration e = hash.keys(); Object obj; while (e.hasMoreElements()) { obj = e.nextElement(); System.out.println(obj + ": " + hash.get(obj)); } }}
HashMap和HashTable的区别
Hashtable继承自Dictionary类,而HashMap是Map interface的一个实现
HashMap允许将null作为一个的key或者value,而Hashtable不允许
还有就是,HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap就必须为之提供外同步
TreeMap
实例9
SortTreeMap.java
package collection;import java.util.Iterator;import java.util.Map;import java.util.TreeMap;public class SortTreeMap { public static void main(String args[]) { String names[] = { "B", "E", "A", "M", "J", "C", "H", "D", "G" }; float diameters[] = { 4800f, 12103.6f, 12756.3f, 6794f, 142984f, 120536f, 51118f, 49532f, 2274f }; Map map = new TreeMap(); for (int i = 0, n = names.length; i < n; i++) { map.put(names[i], new Float(diameters[i])); } Iterator it = map.keySet().iterator(); Object obj; while (it.hasNext()) { obj = it.next(); System.out.println(obj + ": " + map.get(obj)); } }}
二、集合实用类: Collections
在Java集合中,有一个实用类,即java.util.Collections,它的一部分方法专门用于操纵List类型集合,还有一部分方法可用于操纵所有的Collection类型或Map类型的集合。
List代表长度可变的数组,Collections的以下方法适用于List类型的集合。
以下方法适用于Collection类型或Map类型的集合
实例10
collection.java
package collection;import java.util.*;public class collection {public static void main(String[] args) { ArrayList arrayList1=new ArrayList(); arrayList1.add(new Integer(1)); arrayList1.add(new Integer(9)); arrayList1.add(new Integer(3)); arrayList1.add(new Integer(7)); arrayList1.add(new Integer(8)); arrayList1.add(new Integer(2)); arrayList1.add(new Integer(5)); arrayList1.add(new Integer(4)); arrayList1.add(new Integer(6)); System.out.print("目前ArrayList1数据内容如下:"); System.out.println(arrayList1); Collections.sort(arrayList1); System.out.println("排序后的内容如下:"+arrayList1); Collections.reverse(arrayList1); System.out.println("反排序后的内容如下:"+arrayList1); Collections.shuffle(arrayList1); System.out.println("重新洗牌后数据内容如下:"+arrayList1); System.out.println("最大值"+Collections.max(arrayList1)); System.out.println("最小值"+Collections.min(arrayList1)); }}
三、集合类中排序
在JDK类库中,有一部分类实现了Comparable接口中,如Integer、Double和String等。Comparable接口有一个compareTo(Object o)方法,它返回整数类型。对于表达式x.compareTo(y),如果返回值为0,则表示x和y相等地,如果返回值大于0,则表示x大于y,如果返回值小于0,则表示x小于y。
在TreeSet调用对象compareTo()方法比较集合中对象的大小
实例11
ComparatorTest.java
package collection;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.Comparator;import java.util.List; class Person implements Comparable { String firstName, lastName; public Person(String f, String l) { this.firstName = f; this.lastName = l; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public String toString() { return "[ name=" + firstName + ",name=" + lastName + "]"; } public int compareTo(Object obj) { Person emp = (Person) obj; int deptComp = firstName.compareTo(emp.getFirstName());return ((deptComp == 0) ? lastName.compareTo(emp.getLastName()) : deptComp); } public boolean equals(Object obj) { if (!(obj instanceof Person)) { return false; } Person emp = (Person) obj; return firstName.equals(emp.getFirstName()) && lastName.equals(emp.getLastName()); }}public class ComparatorTest implements Comparator { public int compare(Object obj1, Object obj2) { Person emp1 = (Person) obj1; Person emp2 = (Person) obj2; int nameComp = emp1.getFirstName().compareTo(emp2.getFirstName()); return ((nameComp == 0) ? emp1.getLastName().compareTo( emp2.getLastName()) : nameComp); } public static void main(String args[]) { String names[] = { "张三", "李四", "王五", "赵六", "陈七", "孙八", "周九" }; // Convert to list List list = new ArrayList(Arrays.asList(names)); // Ensure list sorted Collections.sort(list); System.out.println("List排序: [length: " + list.size() + "]"); System.out.println(list); // Search for element in list int index = Collections.binarySearch(list, "李四"); System.out.println("发现位置 " + index); // Search for element not in list index = Collections.binarySearch(list, "、楚一"); System.out.println("没有发现楚一" + index); // Insert int newIndex = -index - 1; list.add(newIndex, "冯二"); System.out.println("增加了冯二: [length: " + list.size() + "]"); System.out.println(list); // Min should be Bart System.out.println(Collections.min(list)); // Max should be Roy System.out.println(Collections.max(list)); Comparator comp = Collections.reverseOrder(); // Reversed Min should be Roy System.out.println(Collections.min(list, comp)); // Reversed Max should be Bart System.out.println(Collections.max(list, comp)); }}四、集合类的历史
四、集合类的历史
在早期JDK1.0版本中,代表集合的类只有Vector、Stack、Enumeration、Hashtable、Properties。从JDK1.2版本中开始,才出现了Collection、Set、List和Map接口及各种实现类。它们构成了完整的集合框架。JDK10.版本中的集合类也称历史集合类
历史集合类
历史集合类
描述
缺点
新集合框架的替代类
Vector
集合中的元素有索引位置,在新的集合框架中把它改为实现了List接口
采用了同步机制,影响操纵集合的性能
ArrayList和LinkedList
Stack
表示堆栈,支持后进先出的操作
采用了同步机制,影响操纵集合的性能:Stack继承了Vector类,使得Stack不能作为严格的堆栈,还允许随机访问
LinkedList
Hashtable
集合中的每一个元素包含一对键与值。在新的集合框架中把它改为实现了Map接口
采用了同步机制,影响操纵集合性能
HashMap
Properties
集合中的每个元素包含一对键与值,继承了Hashtable
采用了同步机制,影响了操纵集合的性能
无
Enumeration
用于遍历集合中元素
只能与Vector和Hashtable等历史集合配套使用:Enumeration类的名字较长,没有Iterator类名字简短
Iterator
从JDK1.2版本开始,对Vector和Hashtable做了修改,使它们分别实现了List和Map接口中。尽管如此,由于Vector、Stack、Hashtable和Enumeration在实现中都使用了同步机制,并发性能差,因此不提倡使用它们,
Properties类是一种特殊的Map类,它继承了Hashtable(Object,Object)类。Properties类的load()方法可用来从输入流中读取键与值
实例12
myapp.properties
color=redshape=circleuser=Tom
PropertiesTester.java
package collection;import java.util.*;import java.io.*;public class PropertiesTester{ public static void print(Properties ps){ Set keys=ps.keySet(); Iterator it=keys.iterator(); while(it.hasNext()){ String key=(String)it.next(); String value=ps.getProperty(key);//使用getProperty可以返回myapp.properties文件中的一个属性 System.out.println(key+"="+value); } } public static void main(String args[])throws IOException{ Properties ps=new Properties(); //myapp.properties文件与PropertiesTester类的.class文件位于同一个目录下 InputStream in=PropertiesTester.class.getResourceAsStream("myapp.properties"); ps.load(in);//把输入流中的数据加载到Properties对象中 print(ps); ps=System.getProperties();//该方法返回一个Properties对象,在这个对象中包含了一系列的系统属性 print(ps); }}
小结:
我们介绍了几种常用Java集合类的特性和使用方法。为了保证集合正常工作,有些集合类对存放的对象有特殊的要求:
HashSet和HashMap具有好的性能,是Set和Map首选的实现类,只有在需要排序的场合,才考虑用TreeSet和TreeMap。LinkedList和ArrayList各有优缺点,如果经常对元素执行插入和删除操作,那么可用LinkedList,如果经常随机访问元素,那么可用ArrayList.
课后习题:
1. Set和List有哪些区别?
2. Collection与Collections有什么区别?
3. 比较Java数组、ArrayList和LinkedList在查询和存取元素方面的性能
4. HashMap和HashTable的区别
5. 编写一个程序,读入一系列名字并将它们存储在LinkedList中,不能存储重复的名字,并允许用户查找一个名字。
附录
- JAVA 集合 的 集合
- [集合]Java的集合框架 Collection集合
- JAVA集合-集合的遍历
- Java的集合框架
- JAVA集合的认识
- java集合的总结!
- java 对象的集合
- java 当中的集合
- JAVA集合的认识
- Java的集合框架
- java 集合的使用
- java的集合类
- Java的集合对象
- Java集合的数据结构
- Java对象的集合
- Java的集合类
- java的集合
- java的集合对象
- sizeof详解
- QT之ui.和ui->问题
- PHP中文件包含语句的区别
- 汪星人”也选秀 狗狗闯“魔鬼赛道”引关注
- 清华梦的粉碎——写给清华大学的退学申请
- java的集合
- Chrome29的BUG:刷新网页后并未实现WebSocket关闭握手
- php 配置
- 软件概要设计与详细设计的区别
- OPENGL坐标变换
- java i/o黑马程序员学习笔记(2)
- Windows has triggered a breakpoint in XXX.exe.
- IOS 贝塞尔曲线UIBezierPath方法总结
- 将maven项目打包为可执行jar