第十一章 - 持有对象

泛型和类型安全的容器

   java se5之前容器是没有泛型的,以ArrayList为例,所有的都是ArrayList<Object>的,所以它允许向容器中插入任何类型的对象,这样做会有很多问题出现,进去的是详细的类型,而出来是确是Object的了,如果要使用就要强制类型转换,转换错了,程序就会抛出错误

   java SE5 之后引入的了泛型,如果想容器中插入类型错误的对象,编译器会报告警告异常。如ArrayList<String> 插入int型数据,泛型将运行期的错误提升到了编译期间。

基本概念

   Java容器的用途是“保存对象”,并将其划分为两个不同的概念

   Collection:一个独立元素的序列,List必须按照插入的顺序保存对象,Set不能有重复的对象,Queue按照排队规则来确定对象产生的顺序。

  Map:一组成对的“键值对”,允许使用键来查找值。

添加一组元素

   Collection.addAll()方法接受一个Collection对象,以及一个数组或逗号分隔的list对象,将其添加到Collection中。 

   Arrays.adList()方法接受一个数组或者是逗号分隔的元素列表,并转换成一个List对象。

public class Test {
    public static void main(String[] args) {
        Collection<Integer> collection =
                new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5));
        System.out.println(collection);

        Integer[] moreInts = { 6, 7, 8, 9, 10 };
        collection.addAll(Arrays.asList(moreInts));
        System.out.println(collection);

        Collections.addAll(collection, 11, 12, 13, 14, 15);
        System.out.println(collection);

        Collections.addAll(collection, moreInts);
        System.out.println(collection);

        List<Integer> list = Arrays.asList(16, 17, 18, 19, 20);
        System.out.println(list);

        list.set(1, 99);
        System.out.println(list);

//        list.add(21); // 报错

    }
}

   注意:Arrays.asList()转换的list对象,是不能修改长度的,比如add方法,delete方法等。

容器的打印

   

public class test2 {

        static Collection fill(Collection<String> collection) {
            collection.add("rat");
            collection.add("cat");
            collection.add("dog");
            collection.add("dog");
            return collection;
        }
        static Map fill(Map<String,String> map) {
            map.put("rat", "Fuzzy");
            map.put("cat", "Rags");
            map.put("dog", "Bosco");
            map.put("dog", "Spot");
            return map;
        }
        public static void main(String[] args) {
            System.out.println(fill(new ArrayList<String>()));
            System.out.println(fill(new LinkedList<String>()));
            System.out.println(fill(new HashSet<String>()));
            System.out.println(fill(new TreeSet<String>()));
            System.out.println(fill(new LinkedHashSet<String>()));
            System.out.println(fill(new HashMap<String,String>()));
            System.out.println(fill(new TreeMap<String,String>()));
            System.out.println(fill(new LinkedHashMap<String,String>()));
        }
    
}

      

   这里展示了java容器的两种主要类型,他们的区别在于在容器中每个槽保存的元素个数Collection每个槽保存一个元素,Map每个槽保存两个对象,即键与关联的值。

   ArrayList和LinkedList都是按照插入顺序保存对象,区别在于执行某些操作时候的性能。HashSet,TreeSet,LinkedHashSet都是set类型,每个相同的项只保存一次。

   HashSet使用很复杂的方式存储元素,后面介绍,它是最快的获取元素方式。如果存储顺序很重要,可以使用TreeSet,按照比较结果的升序保存对象,或者使用LinkedHashSet,它按照添加的顺序保存对象。 

   HashMap也提供了最快的查询速度,也没有顺序保存元素,TreeMap按照比较结果保存键,LinkedHasMap按照插入顺序保存,同时保留了HashMap的查询速度。

List

   List 将元素维护在特定的序列中,有两种类型: 
(1)基本的ArrayList,它长于随机访问元素,但是在List中间插入和移除元素时较慢。 
(2)LinkedList,在List中间进行插入和删除操作代价较低,但是在随机访问方面相对较慢,但是它的特性集较ArrayList更大。

在List中,一些函数的用法: 
(1)contains()方法来确定某个对象是否在对象中。 
(2)remove()方法用来移除某个对象。 
(3)如果你有一个对象的引用,可以使用indexOf()来确定该对象在List中所处的位置的索引编号。 
(4)subList()方法用来从较大的列表中创建出一个片段。 
(5)retainAll()方法用来求交集。 
(6)removeAll()方法用来移除在参数List中的所有元素。 
(7)addAll()方法用来在初始List的中间插入新的列表。

迭代器 


   迭代器是一个对象,它的工作是遍历并选择序列中的对象。从而做到了只是使用容器而不关心容器的类型。 
在我看来,Java中的Iterator类似于数据结构中的单向链表,只能单向移动。只能用来: 
(1)使用方法iterator()要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素。 
(2)使用next()获得序列中的下一个元素。 
(3)使用hasNext()检查序列中是否还有元素。 
(4)使用remove()将迭代器新近返回的元素删除。 

ListIterator是一个更强大的Iterator的子类型。只能用于各种List类的访问,但是可以双向移动。 
(1)nextIndex()用来指向当前位置的后一个元素的指引。 
(2)previousIndex()用来指向当前位置的前一个元素的指引。 
(3)listIterator()方法产生一个指向List开始处的ListIterator。 
(4)listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。

LinkedList 


   LinkedList也像ArrayList一样实现了基本的List接口,但是它执行某些操作(在List中间插入和移除)是比ArrayList操作方面要逊色一些。LinkedList还添加了可以使其用作栈、队列或双端队列的方法。这些方法中有些有些彼此之间只是名称有些差异,或者只存在这些许差异,以使得这些名字在特定用法的上下文环境中更加适用。例如,getFirst()和element()完全一样,它们都返回列表的头,而并不移除它,如果List为空,则抛出NoSuchElementExcetion。peek()方法与这两个方式只是稍有差异,它在列表为空是返回null。 
removeFirst()与remove()也是完全不一样的,它们移除并返回列表的头,而在列表为空时抛出NoSuchElementExcetion。poll()稍有差异,它在列表为空是返回null。addfirst()与add()和addLast()相同,它们将某个元素插入到列表的尾部。removeLast()移除并返回列表的最后一个元素。

Stack

   栈通常指后进先出的容器。 pop():返回并移除栈顶元素。 peek():返回栈顶元素,不移除。Stack可以基于LinkedList实现

Set

    Set不保存重复的元素。Set中最常被使用的是测试归属性,你可以很容易地询问某个对象是否在某个Set中。正因如此,查找就成为了Set中最重要的操作,因此你通常都会选择一个HashSet的实现,它专门对快速查找进行了优化。TreeMap基于红黑树,有序。LinkedHashSet基于链表,有序

Queue

   LinkedList提供了方法以支持队列的行为,并且实现了Queue接口。

ublic class QueueDemo{
    public static void printQ(Queue queue) {
    while(queue.peek() != null)
     System.out.print(queue.remove() + " ");
    System.out.println();
    }
    public static void main (String[] args){
        Queue<Integer>  queue = new LinkedList<Integer>();
        Random rand = new Random(47);
        for(int i = 0; i < 10; i++)
            queue.offer(rand.nextInt(i + 10));
        printQ(queue);
        Queue<Character> qc = new LinkedList<Charactor>();
        for(char c: "Brontosaurus".toCharArray())
             qc.offer(c);
        printQ(qc);
    }
}/*Output
8 1 1 1 5 14 3 1 0 1
B r o n t o s a u r u s 
*///

   offer()方法在允许的情况下,将一个元素插入到队尾,或者返回false。 
peek()和element()都将在不移除的情况下返回对头,但是peek()方法在队列为空时返回null,而element()会抛出NoSuchElementException异常。 
poll()和remove()方法将移除并返回队头,但是poll()在队列为空时返回null,而remove()会抛出NoSuchElementException异常。

Collection和Iterator

   Collection是描述所有序列容器的共性接口。 
   AbstractCollection提供了Collection的默认实现。可以通过继承AbstractCollection避免重复代码。实现collection就必须实现iterator();
生成Iterator是将队列与消费队列的方法连接在一起耦合度最小的方式,并且与实现Collection相比,在序列上施加的约束也比较少。

Foreach与迭代器  

  foreach语法主要用于数组,但是它也可以应用于任何Collection对象。

总结

   数组将数字与对象联系起来。
   Collection保存单一的元素,而Map保存相关联的键值对。
   List也建立数字索引与对象的关联。
   如果要进行大量随机访问,就使用ArrayList,如果经常从中间插入或删除元素,则应该使用LinkedList。
   各种Queue以及栈行为,由LinkedList支持。
   Map是一种将对象与对象相关联的设计。HashMap用来快速访问,TreeMap保持“键”始终处于排序状态。
   Set不接受重复元素。HashSet提供最快查询速度,TreeSet保持元素处于排序状态。LinkedSet以插入顺序保存元素。
   新程序中不应使用过时的Vector,HashTable和Stack 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值