java总结(之一)--容器的基本用法

来源:互联网 发布:家庭生活记账软件 编辑:程序博客网 时间:2024/06/06 07:16

容器部分归纳为三篇来写,分别从基本用法,深入研究,以及在算法中的应用。本章主要介绍基本用法。
Java中有多种方式保存对象,比如简单的数组,它是编译器支持的类型。数组是保存一组对象的最有效的方式,如果想保存一组基本类型数据,这也是常推荐的方式。但数组具有固定的尺寸,通常在写程序中不知道有多少对象要保存,或者有更复杂的方式来保存时,数组尺寸固定不足就显现出来,下面主要介绍java类库提供的一套完整的容器类,容器提供了许多完善的方法来保存和操作对象,并且可以自动调整自己的尺寸大小。
简单的容器分类

上图是简单的容器分类关系图,从图中可以看出集合类主要分两大接口类,Collection和Map。还有两个工具类Collections和Arrays。下面分别介绍Collection和Map的实现子接口的常用方法及实现。

  • Collection。一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入的顺序保存元素,而Set不能有重复元素。Queue按照排队规则来确定对象产生的顺序(通常与他们被插入的顺序相同)。
  • Map。一组成对的“键值对”对象,允许使用键来查找值。ArrayList允许你使用数字来查找值,因此在某种意义上讲,它将数字关联了起来。映射表允许我们使用另一个对象来查找某个对象,它也被称为“关联数组”。因为它将某些对象与另外一些对象关联在了一起也被成为“字典”。所以Map是强大的编程工具。

collection接口

collection接口概括了序列的概念——一种存放一组对象的方式。任何继承自Collection的类的对象都可以正常使用其所有方法工作。Collection的常用方法以及利用工具类。

  1. 添加一组元素
    在java.util包中的Arrays和Collections类中都有很多实用的方法,可以在一个Collection中添加一组元素。Array.asList()方法接受一个数组或是用逗号隔开的一组元素列表并将其转换为一个List对象。Collections.addAll()方法接受一个Collection对象,将其添加到Collection中。
public class CollectionFuctions {    public static void main(String[] args) {        Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5));        Integer[] moreIntegers = {6,7,8,9,0};        collection.addAll(Arrays.asList(moreIntegers));        Collections.addAll(collection, 11,12,13);        Collections.addAll(collection, moreIntegers);        List<Integer> list = Arrays.asList(14,15,16);//此方法的输出底层表示的是数组,不能调整尺寸大小所以delete()或add()不可用        list.set(1, 20);        System.out.println(collection);        System.out.println(list);    }}
  1. 容器打印
    通常必须使用Arrays.toString()来产生数组的可打印表示,但是打印容器无需任何工具类。
public class CollectionPrint {    static Collection fill(Collection<String> collection){        collection.add("cat");        collection.add("fish");        collection.add("dog");        return collection;    }    static Map fill(Map<String, String> map){        map.put("cat", "haha");        map.put("fish", "hehe");        map.put("dog", "xixi");        return map;    }    public static void main(String[] args) {        System.out.println(fill(new ArrayList<String>()));        System.out.println(fill(new HashSet<String>()));        System.out.println(fill(new HashMap<String,String>()));        System.out.println(fill(new TreeMap<String,String>()));    }}

List

List可以将元素维护在特定的序列中。List接口在Collection的基础上添加了大量的方法使得可以在List的中间插入和移除元素,或者自我调整尺寸。
有两种类型的List:

  • ArrayList,它常用于随机访问元素,但是在List的中间插入和移除元素时较慢。
  • LinkedList,它通过代价较低的在List中间进行的插入和删除操作,提供了优化的顺序访问。LinkedList在随机访问方面相对比较慢,但是它的特性集较ArrayList更大。
  • -

LinkedList

LinkedList也像ArrayList一样实现了List接口,但它执行插入删除是比ArrayList更高效,但在随机访问时更逊色。LinkedList还添加了可以使其用作栈,队列或双端队列的方法。在LinkedList的基础上添加element(), offer(), peek(), poll(), remove()方法使其可以成为一个Queue的实现。但两者中很多方法的意义不同,具体请参考jdk。

迭代器

迭代器(也是一种设计模式)是一个对象,它的工作是遍历并选择序列中的对象,而客户端程序员不必关心该序列底层的结构。此外,迭代器通常被称为轻量级对象:创建它的代价小。java的Iterator只能单向移动,通常

  • 使用方法iterator()要求容器返回一个Iterator。Iterator将准备好的返回序列的第一个元素。
  • 使用next()获取序列下一个元素
  • hasNext()检查序列是否还有元素
  • 使用remove()将迭代器新返回的元素删除
class Pet{    private String name;    public Pet(String name) {        this.name = name;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public String toString() {        return "Pet [name=" + name + "]";    }}public class IteratorTest {    public static void main(String[] args) {        List<Pet> pets =new ArrayList<Pet>(Arrays.asList(new Pet("nick"),new Pet("lily"),new Pet("tom")));        Iterator<Pet> iterator = pets.iterator();        while(iterator.hasNext()){            Pet pet = iterator.next();            System.out.println(pet.getName());        }        iterator = pets.iterator();        for(int i=0;i<2;i++){            iterator.next();            iterator.remove();        }        System.out.println(pets);    }}

Foreach语法主要用于数组,但它也可以用于任何Collection对象。在java中大量的类都是Iterator类型,主要包括所有的Collection类(但是不包括各种Map)。Foreach语法可以用于数组或其他任何Iterator但不意味着数组也是Iterator,而且任何自动包装也不会发生。

ListIterator

ListIterator是一个更加强大的Iterator的子类,它只能用于各种List类的访问,尽管Iterator只能向前移动但是ListIterator可以双向移动,它还可以产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引,并且可以使用set()方法替换它访问过的最后一个元素。

Stack

栈通常是“后进先出”(LIFO)的容器。LinkedList具有能够实现栈的所有功能的方法,因此可以直接将LinkedList作为栈使用。

public class MockStack<T> {    private LinkedList<T> storage = new LinkedList<T>();    public void push( T v){storage.addFirst(v);}    public T peek(){return storage.getFirst();}    public T pop(){return storage.removeFirst();}    public boolean empty(){return storage.isEmpty();}    public String toString(){return storage.toString();}}

Set

Set跟Collection具有完全一样的接口没有任何额外的添加功能,不像前两个不同的List,实际上Set就是Collection,只是行为不同,Set是基于对象的值来确定归属性的。Set不保存重复的元素。Set最常用在被使用的是测试归属性,你可以很容易的询问某个对象是否在某个Set中。因此查找是Set中最重要的操作,因此我们通常会选择一个HashSet的实现,他专门对快速查找进行了优化。

  • HashSet使用了散列,它所维护的顺序与TreeSet或LinkHashSet都不同,它们的实现方式具有不同的元素存储方式。
  • TreeSet将元素存储在红黑树数据结构中,而HashSet使用散列函数。
  • LinkHashSet因为查询速度的原因也使用了散列,但是看起来它使用了链表来维护元素的插入顺序。

Queue

队列是一个典型的先进先出(FIFO)容器,只可从一端插入从另一端删除,通常被当做一种可靠的将对象从程序的某个区域传输到另一个区域的途径。队列在并发编程中特别重要。LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以用作Queue的一种实现。通过LinkedList向上转型为Queue。

PriorityQueue

先进先出描述了最典型的队列规则,是在指定的一组队列中元素的情况下,确定下一个弹出队列的元素的规则,下一个元素应该是等待时间最长的元素。优先级队列声明下一个弹出的元素是最需要的元素(具有最高优先级)。当你在PriorityQueue上调用offer()方法来插入一个对象时,这个对象会在队列中被排序。默认的排序将使用对象在队列中的自然顺序,但我们也可以提供自己的Comparator来修改顺序,PriorityQueue可以确保当你调用peek(), poll(), remove() 方法时获取元素是队列中优先级最高的。

数组

数组与其他种类的容器之间区别有三方面:效率,类型,保存基本类型的能力。数组是一种效率最高的存储和随机访问对象引用序列的方式。数组就是一个简单的线性序列,这使得元素访问非常快。但是为这种速度所付出代价是数组对象的大小固定,并且在其生命周期不可变。虽然首选是ArrayList而不是数组,但ArrayList的效率比数组低很多。数组可以持有基本类型,而泛型之前的容器则不能,但有了泛型容器就可以指定并检查所持有对象的类型。
Comparator 集合外排序 基本类型无法使用
Comparable 集合内使用

Map接口

Map与Collection接口一样可以容易的扩展到多维,而我们只需要将其值设置为Map,但我们可以很容易的将容器组合起来生成更强大的数据结构,如Map

public static void main(String[] args) {  Map<String, String> map = new HashMap<String, String>();  map.put("1", "value1");  map.put("2", "value2");  map.put("3", "value3");  //第一种:普遍使用,二次取值  System.out.println("通过Map.keySet遍历key和value:");  for (String key : map.keySet()) {   System.out.println("key= "+ key + " and value= " + map.get(key));  }  //第二种  System.out.println("通过Map.entrySet使用iterator遍历key和value:");  Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();  while (it.hasNext()) {   Map.Entry<String, String> entry = it.next();   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());  }  //第三种:推荐,尤其是容量大时  System.out.println("通过Map.entrySet遍历key和value");  for (Map.Entry<String, String> entry : map.entrySet()) {   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());  }  //第四种  System.out.println("通过Map.values()遍历所有的value,但不能遍历key");  for (String v : map.values()) {   System.out.println("value= " + v);  } }

总结

  1. 数组将数字与对象联系起来。它保存类型明确的对象,查询对象时,不需要对结果进行类型转换。它可以是多维的,可以保存基本类型的数据不可以保存包装类,数组里没有自动装拆箱。数组一旦生成其容量不可变。
  2. Collection保存单一的元素,而Map保存相关联的键值对。有了泛型我们可以在容器中放指定的类型,因此我们不会将错误的类型对象放置其中并且从中获取时不用类型转换。可以自动更改容器的大小。容器中不可持有基本类型,但是自动包装机制会仔细的执行基本类型到容器中所有的包装器类型之间的双向转换。
  3. 像数组一样,List也建立数字索引与对象的关联。因此,数组与List都是排好的容器,但List能动态扩展。
  4. 如果要大量随机访问就是用ArrayList;如果经常从表中插入和删除元素应使用LinkedList。
  5. 各种Queue以及栈的行为,有LinkedList提供支持。
  6. Map是一种将对象(而非数字)与对象相关联的行为。HashMap设计用来快速访问;TreeMap保持“键”始终处于排序行为,所以没有HashMap快;LinkedHashMap保持元素插入的顺序,但也是通过散列提供了快速访问能力。
  7. Set不接受重复元素无序。HashSet提供最快的查询速度但无序,而TreeSet保持元素处于排序状态。LinkedHashSet以插入顺序保存元素。
  8. 新程序不应该使用过时的Vector、Hashtable和Stack。 Map与Collection之间唯一重叠就是Map可以使用entrySet()和values()方法来产生Collection。
0 0
原创粉丝点击