List接口和Set接口

List接口和Set接口

Collection下面有Set(无序集合,元素不可重复),Queue(队列),List(有序集合,元素可以集合)。
在这里插入图片描述

Set :EnumSet,SortedSet(TreeSet), HashSet(LinkedHashSet)

Queue : Deque(ArrayDeque, LinkedList), Priority

List :ArrayList, Vector(Stack)

Set接口

HashSet类

HashSet是Set接口的典型实现,大多数时候使用Set集合时就是使用这个实现类。HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。

特点:

  1. 不能保持元素的排列顺序,顺序可以与添加顺序不同,顺序也有可能发生变化。
  2. HashSet不是同步的, 如果多个线程同时访问一个HashSet,假设有两个或者两个以上线程同时修改了HashSet集合,则必须通过代码来保证其同步。
  3. 集合元素值可以是null
public class TestInteger {
    public static void main(String[] args) {
        //唯一,无序,底层哈希表实现
        HashSet<Integer> hs = new HashSet<>();
        hs.add(19);
        hs.add(5);
        hs.add(20);
        hs.add(19);
        hs.add(41);
        hs.add(0);

        System.out.println(hs.size());
        System.out.println(hs);

    }
}

LinkedHashSet类

LinekedHashSet说HashSet的子类,LinkedHashSet需要维护元素的插入顺序,因此性能略低于HashSet性能,但在迭代访问Set里的全部元素时将有很好的性能。

底层也是哈希表+链表来实现的

特点: 唯一,有序(按照输入顺序进行输出)

public class LinkedHashSetTest {
    public static void main(String[] args) {
        LinkedHashSet books = new LinkedHashSet();
        books.add("疯狂java讲义");
        books.add("轻量级java EE企业应用实战");
        books.add("疯狂java讲义");
        System.out.println(books);

        books.remove("疯狂java讲义");
        books.add("疯狂java讲义");
        System.out.println(books);
    }
}

TreeSet类

TreeSet是SortSet接口的实现类,TreeSet可以确保集合元素处于排序状态。

特点: 唯一,无序(没有按照输入顺序,进行输出), 有序(按照升序进行遍历)

底层是红黑树

public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet nums = new TreeSet();
        nums.add(5);
        nums.add(2);
        nums.add(10);
        nums.add(-9);

        System.out.println(nums);

        System.out.println(nums.first());

        System.out.println(nums.last());

        System.out.println(nums.headSet(4));

        System.out.println(nums.tailSet(5));

        System.out.println(nums.subSet(-3,4));
    }
}
自然排序

TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列,这种方式就是自然排列。

class R implements Comparable{
    int count;
    public R(int count){
        this.count = count;
    }
    public String toString(){
        return "R[count: "+count+"]";
    }
    public boolean equals(Object obj){
        if (this == obj){
            return true;
        }
        if (obj != null && obj.getClass() == R.class){
            R r = (R) obj;
            return r.count == this.count;
        }
        return false;
    }

    @Override
    public int compareTo(Object obj) {
        R r = (R)obj;
        return count > r.count?1:count <r.count ? -1:0;

    }
}
public class TreeSetTest3 {
    public static void main(String[] args) {
        TreeSet ts = new TreeSet();
        ts.add(new R(5));
        ts.add(new R(-3));
        ts.add(new R(9));
        ts.add(new R(-2));

        System.out.println(ts);

        R first = (R)ts.first();

        first.count = 20;
        System.out.println(ts);

        R last = (R)ts.last();

        last.count = -2;
        System.out.println(ts);


    }
}
定制排序

TreeSet的自然排序是根据集合元素的大小,TreeSet将它们以升序排列。如果需要实现定制排序,则可以通过Comparator接口的帮助。

class M{
    int age;
    public M(int age){
        this.age = age;
    }
    public String toString(){
        return "M [age:"+age+"]";
    }
}
public class TreeSetTest4 {
    public static void main(String[] args) {
        TreeSet ts = new TreeSet((o1, o2) -> {
            M m1 = (M) o1;
            M m2 = (M) o2;
            
            return m1.age > m2.age ?-1:
                    m1.age < m2.age ? 1:0;
            
        });
        ts.add(new M(5));
        ts.add(new M(-3));
        ts.add(new M(9));
        System.out.println(ts);

    }
}

EnumSet类

EnumSet是一个专为枚举类设计的集合类,EnumSet中的所有元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显示或隐式地指定。EnumSet地集合元素也是有序的。EnumSet以枚举值在Enum类内的定义顺序来决定集合元素的顺序。

enum Season{
    SPRING, SUMMER,FALL,WINNER
}
public class EnumSetTest {
    public static void main(String[] args) {
        EnumSet se1 = EnumSet.allOf(Season.class);
        System.out.println(se1);
        EnumSet se2 = EnumSet.noneOf(Season.class);
        System.out.println(se2);
    }
}

各Set实现类的性能分析

HashSet和TreeSet是Set的两个典型实现,到底如何选择呢?

HashSet的性能总是比TreeSet好(特别是最常用的添加,查询元素等操作)
因为TreeSet需要额外的红黑树算法来维护集合元素的次序。
只有当需要一个保持排序的Set时,才应该使用TreeSet,否则都应该使用HashSet

HashSet还有一个子类:

LinkedHashSet,对于普通的插入,删除操作,LinkedHashSet比HashSet要略微慢一点,这是由维护链表所带来的额外开销造成的,但由于有了链表,遍历LinkedHashSet会更快。

EnumSet是所有Set实现类中性能最好的,但它只能保存同一个枚举类的枚举值作为集合元素。

Set的三大实现类HashSet, TreeSet, EnumSet都是线程不安全的。

如果有多个线程同时访问一个Set集合,并且有超过一个线程修改了该Set集合,则必须手动保证该Set集合的同步性。

list接口

List接口和ListIterator

List作为Collection 接口的子接口,当然可以使用Collection接口里的全部方法。

List集合允许使用重复元素,可以通过索引来访问指定位置的集合元素。

public class TestList {
    public static void main(String[] args) {
//        有序,不唯一
        List list = new ArrayList();
        list.add(13);
        list.add(17);
        list.add(6);
        list.add(-1);
        list.add("abc");

        System.out.println(list);
        list.add(3,66);
        System.out.println(list);
        list.set(3,77);
        System.out.println(list);
        list.remove(2);
        System.out.println(list);
        list.remove("abc");
        System.out.println(list);

        Object o = list.get(0);
        System.out.println(o);

//        list集合 遍历
//        方式: 普通for循环
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        for (Object o1 : list) {
            System.out.println(o1);
        }

        Iterator it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }

    }
}

与Set只提供了一个iterator()方法不同,List还额外提供了一个ListIterator()方法,该方法返回一个ListIterator对象,ListIterator接口继承了Iterator接口

public class Test01 {
    public static void main(String[] args) {
//        ArrayList<String> list = new ArrayList<>();
        ArrayList list = new ArrayList();

        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("dd");
        list.add("ee");

        String[] strings = new String[10];


//        错误
//        list与it对集合同时进行操作
//        Iterator<String> it = list.iterator();
//        while (it.hasNext()){
//           if ("cc".equals(it.next())){
//               list.add("kk");
//
//           }
//        }

        ListIterator<String> it = list.listIterator();
        while (it.hasNext()){
            if ("cc".equals(it.next())){
                it.add("kk");
            }
        }
//        System.out.println(it.hasNext());
//        System.out.println(it.hasPrevious());
        逆向遍历
//        System.out.println(it.hasNext());
//        System.out.println(it.hasPrevious());
        while (it.hasPrevious()){
            System.out.println(it.previous());
        }

    }
}

ArrayList和Vector实现类

数组优点: 查询效率高

特点: 数组可以重复

数组缺点: 删除,增加元素效率低

遍历方式相同

方式一: 普通的for循环

方式二: 增强for循环

方式三: 迭代器(Iterator, ListIterator)

ArrayList实现类: 类似于StringBuilder

JDK1.7源码:

底层数组,在调用构造器的时候,数组长度初始化10, 扩容的时候扩展为原数组的1.5倍

JDK1.8源码:

底层数组,在调用构造器的时候,底层数组为{}, 在调用add方法以后底层数组才重新赋值为新数组,新数组的长度为10-》 节省内存,在add后才创建长度为10的数组

Vector实现类

联系: 底层数组都是数组的扩容

区别:

ArrayList底层扩容长度为原数组的1.5倍 线程不安全,效率高

Vector底层扩容长度为原数组的2倍 线程安全 效率低 (淘汰)

Queue集合

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

PriorityQueue 实现类

PriorityQueue 是一个比较准确的队列实现类。之所以说它是比较标准的队列实现,而不是绝对标准的队列实现。,是因为 PriorityQueue 保存队列元素的顺序并不是按加入队列顺序,而是按队列元素的大小进行重新排序。

public class PriorityQueueTest {
    public static void main(String[] args) {
        PriorityQueue pq = new PriorityQueue();
        pq.offer(6);
        pq.offer(-3);
        pq.offer(20);
        pq.offer(18);

        System.out.println(pq);
        System.out.println(pq.poll());

    }
}

Deque 接口与ArrayDeque 实现类

Deque接口是 Queue接口的子接口,它代表一个双端队列,Deque接口里定义了一些双端队列的方法。也可以为栈来使用。

把ArrayDeque 当成 “栈”

public class ArrayDequeStack {
    public static void main(String[] args) {
        ArrayDeque stack = new ArrayDeque();
        stack.push("疯狂Java讲义");
        stack.push("轻量级Java EE企业级应用实战");
        stack.push("疯狂Android");

        System.out.println(stack);

        System.out.println(stack.peek());

        System.out.println(stack);

        System.out.println(stack.pop());

        System.out.println(stack);
    }
}

作为队列使用

public class ArrayDequeQueue {
    public static void main(String[] args) {
        ArrayDeque queue = new ArrayDeque();

        queue.offer("疯狂Java讲义");
        queue.offer("轻量级Java EE企业应用实战");
        queue.offer("疯狂Android讲义");

        System.out.println(queue);

        System.out.println(queue.peek());

        System.out.println(queue);

        System.out.println(queue.poll());

        System.out.println(queue);
    }
}

LinkedList实现类

LinkedList类是List接口的实现类---- 这就意味它是一个List集合,可以根据索引来随机访问集合中的元素。除此之外,LinkedList还实现了Deque接口,可以被当成双端队列使用,因此即可以被当成"栈"来使用,也可以当成队列使用。

public class LinkedListTest {
    public static void main(String[] args) {
        LinkedList books = new LinkedList();
        books.offer("疯狂Java讲义");
        books.push("轻量级Java EE企业应用实战");
        books.offerFirst("疯狂Android讲义");

        for (int i = 0; i < books.size(); i++) {
            System.out.println("遍历中: "+books.get(i));
        }

        System.out.println(books.peekFirst());

        System.out.println(books.peekLast());

        System.out.println(books.pop());

        System.out.println(books);

        System.out.println(books.pollLast());

        System.out.println(books);
    }
}

各List实现类的性能分析

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

  1. 如果需要遍历List集合元素, 对于ArrayList, Vector 集合,使用随机访问方法来遍历集合元素,这样性能更好: 对于LinkedList集合,则应该采用迭代器来遍历集合元素。
  2. 如果需要经常执行插入,删除操作来改变包含大量数据的 List集合的大小,可考虑使用LinkedList集合。使用ArrayList, Vector集合可能需要经常重新分配内部数组的大小,效果可能较差。
  3. 如果有多个线程需要同时访问List集合种的元素,开发者可考虑使用使用Collections将集合包装成线程安全集合。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值