资讯专栏INFORMATION COLUMN

java集合-List

MasonEast / 903人阅读

摘要:会死循环,因为栈内不会弹出所以判断会一直执行。集合用于模拟队列这种数据结构,队列通常是指先进先出的容器。集合不仅提供了的功能,还提供了双端队列,栈的功能。如果有多个线程需要访问集合中的元素,需要考虑使用将几个包装成线程安全集合。

List判断两个对象相等只通过equals方法比较返回true即可。

public class A {
    @Override
    public boolean equals(Object arg0) {
        return true;
    }
}
public class SameAListTest {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        //[1, 2, 3]
        System.out.println(list);
        list.remove(new A());
        //[2, 3]
        System.out.println(list);
        list.remove(new A());
        //[3]
        System.out.println(list);
    }
}

从上面程序可以看出,当程序试图删除一个A对象,List将会调用该A对象的equals方法依次与集合元素进行比较,如果该equals方法以某个集合元素作为参数时返回true,List将会删除该元素,A重写了equals方法,该方法总是返回true。

当调用List的set(int index,Object object)方法来改变List集合指定所引处的元素时,指定的索引必须是List集合的有效索引。例如集合长度是4,就不能指定替换索引为4处的元素--也就是说,set(int index,Object object)方法不会改变List集合的长度。

List还额外提供了一个listIterator方法,该方法返回一个ListIterator对象,ListIterator接口继承了Iterator接口,提供了专门操作List的方法。

public class ListIterators {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add("123");
        list.add("231");
        list.add("132");
        /*正向迭代
         * Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }*/
        /*//从指定的索引以后的元素进行迭代   Lambda迭代
        ListIterator listIterator = list.listIterator(1);
        //231  132
        listIterator.forEachRemaining((e) -> System.out.println(e));*/
        
        ListIterator iterator = list.listIterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            System.out.println(next);
            if ("132".equals(next)) {
                iterator.add("新添加的");
            }
            
        }
        System.out.println("反向迭代 +++++++++++++++++++++");
        while (iterator.hasPrevious()) {
            System.out.println(iterator.previous());
        }
        //[123, 231, 132, 新添加的]
        System.out.println(list);
        /*
         * 123
           231
           132
           反向迭代 +++++++++++++++++++++
           新添加的
           132
           231
           123
           [123, 231, 132, 新添加的]
         */
    }
}

ListIterator与Iterator相比,ListIterator是反向迭代,Iterator是正向迭代,而且ListIterator还可以通过add方法向List集合中添加元素,Iterator只能删除元素、

ArrayList和Vector实现类

ArrayList和Vector类都是基于数组实现的List类,所以ArrayList和Vector类分装了一个动态的,允许再分配的Object[]数组。ArrayList或Vector对象使用initialCapacity参数来设置该数组的长度,当向ArrayList或Vector中添加元素超出了该数组的长度时,他们的initialCapacity会自动增加。

ArrayList和Vector的区别是:ArrayList是线程不安全的,当多个线程访问同一个ArrayList集合时,如果有超过一个线程修改了ArrayList集合,则程序必须手动保证该集合的同步性,但Vector集合则是线程安全的,无须程序保证该集合的同步性。因此Vector是线程安全的,所以Vector的性能比ArrayList的性能要低;

Vector提供了Stack子类,它用于模拟栈这种数据结构,栈筒仓是指后进先出LIFO的容器,最后push进栈的元素,将最先被pop出栈,出入栈的都是Object,

如果程序需要使用栈这种数据结构,则可以考虑ArrayDeque。

ArrayDeque底层是基于数组实现的,因此性能很好。

public class ArrayListAndVector {
    public static void main(String[] args) {
        Stack vector = new Stack<>();
        vector.push("1");
        vector.push("2");
        vector.push("3");
        while (!vector.empty()) {
            System.out.println(vector.pop());// 3 2 1 
            //System.out.println(vector.peek());  会死循环,因为栈内不会弹出所以判断会一直执行。
        }
    }
}
固定长度的List

Arrays提供了asList(Object...a)方法,该方法可以把一个数组或指定个数的对象转化成一个List集合,这个List集合时Arrays的内部类ArrayList的实例。

Array.ArrayList是一个固定长度的List集合,程序只能遍历该集合里的元素,不可增加,删除该集合里的元素。

public class FixedSizeLists {
    public static void main(String[] args) {
        List asList = Arrays.asList(new String[]{"1","@","#","$"});
        //Exception in thread "main" java.lang.UnsupportedOperationException
        //System.out.println(asList.add("dsdsd"));
    }
}
Queue集合

Queue用于模拟队列这种数据结构,队列通常是指“先进先出FIFO”的容器。队列的头部保存在队列中存放时间最长的元素,队列的尾部保存在队列中存放时间最短的元素。新元素插入offer到队列的尾部,访问元素poll操作会返回队列头部的元素。

Queue接口有一个接口Deque,Deque代表一个双端队列,双端队列可以同时从两端来添加元素,删除元素,因此Deque的实现类即可当成队列使用,也可当成栈使用。Java为Deque提供了ArrayDeque和LinkedList两个实现类。

public class QueueTest {
    public static void main(String[] args) {
        Queue queue = new ArrayDeque<>();
        //将指定元素加入此队列的尾部,当使用有容量限制的队列时,此方法通常比add方法更好。
        queue.offer(44);
        queue.add(2);
        //[44, 2]
        System.out.println(queue);
        queue.add(3);
        //[44, 2, 3]
        System.out.println(queue);
        System.out.println(queue.poll());//44
        System.out.println(queue);//[2, 3]
        System.out.println(queue.peek());//2
        System.out.println(queue);//[2, 3]
        queue.remove();
        System.out.println(queue);//[3]
        queue.add(3434);
        System.out.println(queue);//[3, 3434]
        //返回队列头部元素,但是不删除该元素
        System.out.println(queue.element());//3
        System.out.println(queue);//[3, 3434]
        System.out.println(queue.remove(3434));//true
        System.out.println(queue);//[3]
    }
}
PriorityQueue实现类 priority 优先的

PriorityQueue保存队列元素的元素并不是按加入队列的顺序,而是按队列元素的大小进行重新排序,因此当调用peek方法或者poll方法去除队列中的元素时,并不是取出最先进入队列的元素,而是取出队列中的最小的元素。PriorityQueue已经违反了队列的最基本的原则:先进先出

public class PriorityQueues {
    public static void main(String[] args) {
        PriorityQueue priorityQueue = new PriorityQueue<>();
        priorityQueue.add(12);
        priorityQueue.add(-6);
        priorityQueue.add(-9);
        priorityQueue.add(1);
        //[-9, 1, -6, 12]
        System.out.println(priorityQueue);
        priorityQueue.poll();
        //[-6, 1, 12]
        System.out.println(priorityQueue);
    }
}

PriorityQueue不允许插入null元素,PriorityQueue可以定制排序和自然排序。

PriorityQueue自然排序的元素必须实现Comparable接口,而且应该是同一个类的实例

PriorityQueue不要求队列元素实现Comparable接口。

Deque接口和ArrayDeque实现类

Deque接口是Queue接口的子接口,他代表一个双端队列。

ArrayList和ArrayDeque两个集合类的实现机制基本相同,他们的底层都是采用一个动态的可重新分配的Object[]数组来保存集合元素,当集合元素超出了该数组的容量时,系统会在底层重新分配一个Object[]数组来存储集合元素。

把ArrayDeque当成栈来使用

public class ArryDeque {
    public static void main(String[] args) {
        Deque deque = new ArrayDeque<>();
        deque.push(1);
        deque.push(2);
        deque.push(3);
        deque.push(4);
        //[4, 3, 2, 1]
        System.out.println(deque);
        System.out.println(deque.pop()); // 4
        System.out.println(deque);//[3, 2, 1]
    }
}   //后入先出

把ArrayDeque当成队列使用

public class ArryDeque2 {
    public static void main(String[] args) {
        Deque deque = new ArrayDeque<>();
        deque.offer(1123);
        deque.offer(143);
        deque.offer(-11);
        System.out.println(deque);//[1123, 143, -11]
        System.out.println(deque.poll());//1123
        System.out.println(deque);//[143, -11]
        System.out.println(deque.poll());//143
        System.out.println(deque);//[-11]
    }
}

ArrayDque不仅可以作为栈使用,也可以作为队列使用。

LinkedList实现类

可以根据索引来随机访问集合中的元素,LinkedList还是实现了Deque接口,可以被当成双端队列来使用,因此既可以被当成栈使用,也可以当做为队列使用。

public class LinkedListTest {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList<>();
        //将数组元素加入栈顶
        linkedList.push(1);
        //将数组元素加入栈底
        linkedList.offer(2);
        //[1, 2]
        System.out.println(linkedList);
        //加入栈顶
        linkedList.offerFirst(3);
        //[3, 1, 2]
        System.out.println(linkedList);
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i)); //3 1 2
        }
        //访问但不删除栈底
        System.out.println(linkedList.peekLast());//2
        //[3, 1, 2]
        System.out.println(linkedList);
        //访问但不删除栈顶
        System.out.println(linkedList.peekFirst());//3
        //[3, 1, 2]
        System.out.println(linkedList);
        //访问并删除栈顶
        System.out.println(linkedList.pollFirst());//3
        //[1, 2]
        System.out.println(linkedList);
    }
}

LinkedList和ArrayList和ArrayDeque实现机制完全不同

ArrayList,ArrayDeque内部以数组的形式来保存集合中的元素,因此随机访问几个元素时具有较好的性能,而LinkedList内部以链表的形式来保存集合中的元素,因此随机访问集合元素时性能较差,但在插入,删除元素时性能比较出色,只需要改变指针所指的地址即可。

对于所有的内部基于数组的集合实现,例如ArrayList和ArrayDeque等,使用随机访问的性能比使用Iterator迭代访问的性能要好,因为随机访问会被映射成对数组元素的访问。

各种线性表的性能分析

Java提供的List就是一个线性表接口,而ArrayList,LinkedList又是线性表的两种典型实现:基于数组的线性表和基于链的线性表。Queue代表了队列,Deque代表了双端队列,既可以作为队列使用,又可以当做栈使用。

LinkedList集合不仅提供了List的功能,还提供了双端队列,栈的功能。

一般来说,由于数组以一块连续内存区来保存所有的数组元素,所以数组在随机访问时性能最好,所有的内部以数组作为底层实现的集合在随机访问时性能都比较好。而内部以链表作为底层实现的集合在执行插入,删除操作时有较好的性能。但总体来说,ArrayList的性能比LinkedList的性能要好,因此大部分时候都应该考虑使用ArrayList。

使用List集合的一些建议

如果需要遍历List集合,对于ArrayList,Vector集合,应该是用随机访问方法get来遍历集合元素,这样性能更好。对于LinkedList集合,则应该采用迭代器Iterator来遍历集合元素。

如果需要经常执行插入,删除操作来改变含大量数据的List集合的大小,则可考虑使用LinkedList集合,使用ArrayList,Vector集合可能需要经常分配内部数组的大小,效果可能较差。

如果有多个线程需要访问List集合中的元素,需要考虑使用Collections将几个包装成线程安全集合。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69318.html

相关文章

  • Java集合框架——List接口

    摘要:第三阶段常见对象的学习集合框架接口按照集合框架的继承体系,我们先从中的接口开始学习一概述及功能演示概述在中充当着一个什么样的身份呢有序的也称为序列实现这个接口的用户以对列表中每个元素的插入位置进行精确地控制。线程不安全,效率高。 第三阶段 JAVA常见对象的学习 集合框架——List接口 showImg(https://segmentfault.com/img/remote/14600...

    褰辩话 评论0 收藏0
  • Java编程基础16——Colletion集合

    摘要:集合的长度的是可变的,可以根据元素的增加而增长。如果元素个数不是固定的推荐用集合。线程安全,效率低。相对查询慢线程安全的相对增删慢数组结构底层数据结构是链表,查询慢,增删快。线程不安全,效率高。 1_对象数组的概述和使用 A:案例演示 需求:我有5个学生,请把这个5个学生的信息存储到数组中,并遍历数组,获取得到每一个学生信息。 import net.allidea.bean.Stu...

    TerryCai 评论0 收藏0
  • Java编程基础17——集合(List集合)

    1_(去除ArrayList中重复字符串元素方式)* A:案例演示 需求:ArrayList去除集合中字符串的重复值(字符串的内容相同) 思路:创建新集合方式 import java.util.ArrayList; import java.util.Iterator; public class ArrayList_1_demo { /* 创建新集合将重复元素去掉 * 1.明...

    scola666 评论0 收藏0
  • Java 集合 List

    摘要:集合代表一个元素有序可重复的集合,集合中每个元素都有其对应的顺序索引。集合默认按元素的添加顺序设置元素的索引。 List集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。List集合可以通过索引来访问指定位置的集合元素。List集合默认按元素的添加顺序设置元素的索引。 Java8改进的List接口和ListIterator接口 普通方法 List是有序集合,因此L...

    AlphaWatch 评论0 收藏0
  • Java编程基础18——集合(Set集合

    摘要:并把最终的随机数输出到控制台。方法,在集合中如何存储元素取决于方法的返回值返回,集合中只有一个元素。创建集合对象,传入比较器。 1_HashSet存储字符串并遍历 A:Set集合概述及特点 通过API查看即可 B:案例演示 HashSet存储字符串并遍历 import java.util.HashSet; public class Demo1_HashSet { p...

    SexySix 评论0 收藏0
  • 集合概要学习---粗略

    摘要:集合框架的基本接口类层次结构其中表示接口,表示实现类和在实际开发中,需要将使用的对象存储于特定数据结构的容器中。实例是迭代器,拥有两个方法方法迭代器用于遍历集合元素。返回值则是转换后的数组,该数组会保存集合中的所有元素。 Java Collections Framework是Java提供的对集合进行定义,操作,和管理的包含一组接口,类的体系结构。 Java集合框架的基本接口/类层次结构...

    DesGemini 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<