详解List、Iterator

List

List可以将元素维护在特定的序列中。List接口在Collection的基础上添加了大量的方法,使得可以在List的中间插入和移除元素。

两种基本的List类型:

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

基本Api

public static void main(String[] args) {
        /*
         * 因为该List会有插入和删除情况,所以我使用了LinkedList
         * add为插入对象
         * remove为移除对象
         * get是获取对应索引的对象
         * indexOf获取对象对应的索引
         * subList截取部分List,截取的List不能用List的实现类来接受,否则出现异常 java.lang.ClassCastException
         * containsAll 判断参数集合是否属于另一个集合
         */
        LinkedList<String> pets = new LinkedList<String>();
        pets.add("Rat");
        pets.add("Manx");
        pets.add("Cymric");
        pets.add("Mutt");
        pets.add("Pug");
        pets.add("Cymric");
        pets.add("Pug");
        System.out.println("1: " + pets);
        pets.add("Hamster");
        System.out.println("2: " + pets);
        System.out.println("3: " + pets.contains("Hamster"));
        pets.remove("Hamster");
        String p = pets.get(2);
        System.out.println("4: " + p + " " + pets.indexOf(p));
        System.out.println("5: " + pets.indexOf("cymric"));
        System.out.println("6: " + pets.remove("cymric"));
        System.out.println("7: " + pets.remove(p));
        System.out.println("8: " + pets);
        pets.add(3, "Mouse");
        System.out.println("9: " + pets);
        List<String> sub = pets.subList(1, 4);
        System.out.println("subList: " + sub);
        System.out.println("10: " + pets.containsAll(sub));
        Collections.sort(sub);
        System.out.println("sorted subList: " + sub);
        System.out.println("11: " + pets.containsAll(sub));
        Collections.shuffle(sub);
        System.out.println("12: " + pets.containsAll(sub));
    }
    //out put
    1: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug]
    2: [Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug, Hamster]
    3: true
    4: Cymric 2
    5: -1
    6: false
    7: true
    8: [Rat, Manx, Mutt, Pug, Cymric, Pug]
    9: [Rat, Manx, Mutt, Mouse, Pug, Cymric, Pug]
    subList: [Manx, Mutt, Mouse]
    10: true
    sorted subList: [Manx, Mouse, Mutt]
    11: true
    shuffle subList: [Mouse, Manx, Mutt]
    12: true
上述代码,在输出11和12行会发现,打乱截取的sub对containsAll()的结果没有影响。subList()所产生的列表的幕后就是初始列表,因此,对返回的列表修改都会反映到初始列表中,反之亦然。
当确定一个元素是否属于List,发现某个元素的索引,以及从某个List中移除一个元素时,都会用到equals()方法。

retainAll()方法是一种有效的“交集”操作。保留两个比较集合的共同元素。但是此行为依赖equals()方法。
在remove()元素时,如果参数是对象那么则需要考虑equals方法,如果参数是索引,则不需要。因为索引能很直观表示需要移除哪一个元素。
removeAll()也是基于equals的。用法是:从当前List中移除和参数List一样的元素。
Set()方法建议不适用,因为它和Set类显得冲突。可以用replace替换。它表示在指定的索引处(第一个参数),用第二个参数替换整个位置的元素。
addAll()在List中,其重载了Collection中的addAll()方法。如果只填写一个参数,则表示追加在末尾,如果是两个参数,第一个是追加位置的索引。在参数被addAll后,该参数的元素已经发生了变化,如果还有继续使用该参数则会异常。
isEmpty()判断该集合是否为空。
clear()清空当前集合,集合为空不为null。
toArray(),将任意的Collection转换为一个数组。这是一个重载方法,其无参数版本返回Object数组。

迭代器

任何的容器类,都必须有某种方法可以插入和取出元素。例如:List的add()和get()。
但是它们有一个缺点:如果要使用容器,就要对容器进行确切类型的编程。如果原本对List进行的编码,但是后台发现放在Set更好,我们肯定很不愿意重新来写之前的代码,并且一步步放入Set容器。
迭代器则可以实现该目的。迭代器是一个对象,它的工作是遍历并选择序列中的对象,而客户端程序员不必知道或者关系序列底层的结构。此外,迭代器通常被称为轻量级对象:创建它的代价很小。

Iterator
1)使用iterator()要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素。
2)使用next()获得序列的下一个元素。
3)使用hasNext()检查序列是否还有元素。
4)remove()将迭代器新返回的元素删除。
public static void main(String[] args) {

        LinkedList<String> pets = new LinkedList<String>();
        pets.add("Rat");
        pets.add("Manx");
        pets.add("Cymric");
        pets.add("Mutt");
        pets.add("Pug");
        pets.add("Cymric");
        pets.add("Pug");
        Iterator<String> it = pets.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }
有了Iterator就不必要为容器元素的数量操心了。那是右hasNext和next来关心的。
如果只是遍历List,而不对List对象本身做修改的话,foreach语法更加简洁,但是foreach开销更大。
Iterator还可以移除由next产生的最后一个元素,这意味着在调用remove之前必须先调用next。
接受对象容器并传递它,从而在每个对象上都执行操作,这是十分强大的OOP思想。
public static void display(Iterator<String> it){
        int a = 1;
        while(it.hasNext()){
            System.out.print(" " + a +": " + it.next());
            a++;
        }
        System.out.println();
    }
    public static void main(String[] args) {
        LinkedList<String> pets1 = new LinkedList<String>();
        pets1.add("Rat");
        pets1.add("Manx");
        pets1.add("Cymric");
        pets1.add("Mutt");
        ArrayList<String> pets2 = new ArrayList<String>();
        pets2.add("Rat");
        pets2.add("Manx");
        pets2.add("Cymric");
        pets2.add("Mutt");
        HashSet<String> pets3 = new HashSet<String>();
        pets3.add("Rat");
        pets3.add("Manx");
        pets3.add("Cymric");
        pets3.add("Mutt");
        TreeSet<String> pets4 = new TreeSet<String>();
        pets4.add("Rat");
        pets4.add("Manx");
        pets4.add("Cymric");
        pets4.add("Mutt");
        display(pets1.iterator());
        display(pets2.iterator());
        display(pets3.iterator());
        display(pets4.iterator());
    }
上述代码需要注意的是,display()不包含任何有关它所遍历的序列的类型信息,而这也展示了Iterator的真正用处:能够将遍历序列的操作和序列底层的结构分离。我也可以说,迭代器统一了对容器的访问方式。

ListIterator

ListIterator是更加强大的Iterator的子类型,它只能用于各种List的访问。尽管Iterator只能向前移动,但是ListIterator可以双向移动。它还可以产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引,并且可以使用set()方法替换它访问过的最后一个元素。你可以通过调用listIterator()方法产生一个指向List开始处的ListIterator,并且还可能通过调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。下面的例子就是展示这些功能:
public static void main(String[] args) {
        LinkedList<String> pets1 = new LinkedList<String>();
        pets1.add("Rat");
        pets1.add("Manx");
        pets1.add("Cymric");
        pets1.add("Mutt");
        ListIterator<String> it = pets1.listIterator();
        int a = 0;
        while(it.hasNext()){
            System.out.print(" " + a +": " + it.next() + ", nextIndex: " + it.nextIndex() + ", previousIndex: " + it.previousIndex() + "; ");
            a++;
        }
        System.out.println();
        while(it.hasPrevious()){
            System.out.print(" " + a +": " +it.previous());
            a++;
        }
        System.out.println();
        System.out.println(pets1);
        it = pets1.listIterator(3);
        while(it.hasNext()){
            it.next();
            it.set("1");
        }
        System.out.println(pets1);
    }
    //out
     0: Rat, nextIndex: 1, previousIndex: 0;  1: Manx, nextIndex: 2, previousIndex: 1;  2: Cymric, nextIndex: 3, previousIndex: 2;  3: Mutt, nextIndex: 4, previousIndex: 3; 
 4: Mutt 5: Cymric 6: Manx 7: Rat
[Rat, Manx, Cymric, Mutt]
[Rat, Manx, Cymric, 1]

LinkedList

LinkedList和ArrayList一样实现了基本的List接口。但是它执行某些操作时比ArrayList快(在List中间插入和移除),在访问方面没有ArrayList快。

LinkedList添加了可以使其用做栈,队列,或双端队列的方法。
其中有些方法只是名称有差异,或者只有些许差异。

比如:getFirst()和element()他们完全一样,都是返回列表的头,而并不移除它,如果List为空,则抛出NoSuchElementException。peek()方法与他们稍有差异,就是在List为空时,返回null。
removeFirst()和remove()也是完全一样的,它们移除并返回列表的头,而在列表为空时抛出NoSuchElementException。poll()返回null。
addFirst()、add()、addLast()相同,它们都将某个元素插入到列表的尾端。
removeLast()移除并返回列表的最后一个元素。

在Queue接口中,我们可以看见,它在LinkedList的基础上添加了element()、offer()、peek()、poll()、remove()方法,以使其可以成为一个Queue的实现。
下节会将到栈,Set,Map,Queue。容器是应用层数据存储的核心,篇幅很多。关于容器的深入研究会在I/O结束开始进行。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值