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集合(只包括SetList)通用方法。

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接口主要有两个实现类:HashSetTreeSetHashSet类按照哈希算法来存取集合中的对象,存取速度比较快。HashSet类还有一个子类LinkedHashSet类,它不仅实现了哈希算法,而且实现了链表数据结构,链表数据结构能提高插入和删除元素的性能。TreeSet类实现了SortedSet接口中,具有排序功能。

List(列表)

List的主要特征是其元素以线性方式存储,集合中允许存放重复对象。List接口主要的实现类包括:

l  ArrayListArrayList代表长度可变的数组。允许对元素进行快速的随机访问,但是向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对象,然后向集合中加入4Integer对象

 

实例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

ArrayListArrayList代表长度可变的数组。允许对元素进行快速的随机访问,它允许所有元素,包括nullArrayList线程不同步的,向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接口

ListlistIterator()方法返回一个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));    }  }}


 

HashMapHashTable的区别

 

Hashtable继承自Dictionary类,而HashMapMap interface的一个实现

HashMap允许将null作为一个的key或者value,而Hashtable不允许

还有就是,HashMapHashtablecontains方法去掉了,改成containsvaluecontainsKey。因为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接口中,如IntegerDoubleString等。Comparable接口有一个compareTo(Object o)方法,它返回整数类型。对于表达式x.compareTo(y),如果返回值为0,则表示xy相等地,如果返回值大于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版本中,代表集合的类只有VectorStackEnumerationHashtableProperties。从JDK1.2版本中开始,才出现了CollectionSetListMap接口及各种实现类。它们构成了完整的集合框架。JDK10.版本中的集合类也称历史集合类

历史集合类

历史集合类

描述

缺点

新集合框架的替代类

Vector

集合中的元素有索引位置,在新的集合框架中把它改为实现了List接口

采用了同步机制,影响操纵集合的性能

ArrayListLinkedList

Stack

表示堆栈,支持后进先出的操作

采用了同步机制,影响操纵集合的性能:Stack继承了Vector类,使得Stack不能作为严格的堆栈,还允许随机访问

LinkedList

Hashtable

集合中的每一个元素包含一对键与值。在新的集合框架中把它改为实现了Map接口

采用了同步机制,影响操纵集合性能

HashMap

Properties

集合中的每个元素包含一对键与值,继承了Hashtable

采用了同步机制,影响了操纵集合的性能

Enumeration

用于遍历集合中元素

只能与VectorHashtable等历史集合配套使用:Enumeration类的名字较长,没有Iterator类名字简短

Iterator

JDK1.2版本开始,对VectorHashtable做了修改,使它们分别实现了ListMap接口中。尽管如此,由于VectorStackHashtableEnumeration在实现中都使用了同步机制,并发性能差,因此不提倡使用它们,

 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集合类的特性和使用方法。为了保证集合正常工作,有些集合类对存放的对象有特殊的要求:

HashSetHashMap具有好的性能,SetMap首选的实现类,只有在需要排序的场合,才考虑用TreeSetTreeMapLinkedListArrayList各有优缺点,如果经常对元素执行插入和删除操作,那么可用LinkedList,如果经常随机访问元素,那么可用ArrayList.

课后习题:

1.       SetList有哪些区别?

2.       CollectionCollections有什么区别?

3.       比较Java数组、ArrayListLinkedList在查询和存取元素方面的性能

4.       HashMapHashTable的区别

5.       编写一个程序,读入一系列名字并将它们存储在LinkedList中,不能存储重复的名字,并允许用户查找一个名字。

 

附录

 

0 0
原创粉丝点击