Java中的集合是我们编程中常用的东西,集合的作用是用来存放对象的,让我更好的管理对象!

Java集合分为三类:List、Queue、Set

1、List

List是一个集合,按照元素插入的先后顺序进行排列。

javaArrayList元素的下标_java


1.1、ArrayList

ArrayList的底层是数组,当空间不足的时候,会进行动态扩容。

数组的好处就是随机存储块,但是插入和删除效率不高,删除需要搬运元素,插入有的时候需要动态扩容。

ArrayList是线程不安全的,没有加锁,会出现线程不安全问题

ArrayList需要注意的就是遍历删除指定的元素,这点有点坑。

//错误代码
ArrayList<String> list = new ArrayList<String>();
list.add("jaychou");
list.add("jaychou");
list.add("jay");

for (int i = 0;i < list.size();i++){
    if(list.get(i).equals("jaychou")){
        list.remove(i);
    }
}

上面的代码其实是有问题的,因为当删除下标为0第一个"jaychou"的时候,后面的那个“jaychou”,会被移动到下标为0的位置,而下次循环的时候i变成了1,第二个"jaychou"就侥幸逃脱了。

如果通过list.remove(“jaychou”),跟上面的效果是一样的。

//正确代码
int i = 0;
while(i < list.size()){
    if(list.get(i).equals("jaychou")){
        list.remove(i);
    }else{
        i++;
    }
}

上述代码才能正确的删除。

也可以通过Iterator来删除

Iterator<String> it = list.iterator();
while (it.hasNext()){
    if (it.next().equals("jaychou")){
        it.remove();
    }
}

创建不变的ArrayList集合

List<String> list = Arrays.asList("jaychou","jaychou");

通过Arrays.asList(),创建的list无法插入和删除元素,会报错!
这种创建的ArrayList的效率更高。

2、Vector
和ArrayList几乎一致,底层都是数组实现的,只不过Vector是线程安全的。
删除等方法都和ArrayList一致

3、LinkedList
LinkedList的底层结构是链表,特点就是删除和插入效率高,查询效率低。

LinkedList除了当线性表外,还可以当Queue,也就是队列。

LinkedList的底层是双向链表,类中实现了首尾节点,实现了双端队列。

add(E e):向队尾加入元素
poll():从队首弹出并返回元素
peek():获取队首元素
addFirst(E e):向队首中加入元素
removeFirst():从队首弹出并返回元素
peekFirst():获取队首元素
addLast(E e):向队尾加入元素
removeLast():从队尾弹出并返回元素
peekLast():获取队尾元素

LinkedList也是线程不安全的。

名称

底层实现

线程安全

ArrayList

数组


Vector

数组


LinkedList

双向链表


2、Queue

Queue就是我们熟知的队列

javaArrayList元素的下标_java_02

这里我们只说下常用的LinkedList和优先队列PriorityQueue和ArrayDeque
LinkedList上面我们已经说过了不在说了

ArrayDeque
ArrayDeque也是双端队列,和LinkedList一样,只不过LinkedList的底层是链表实现的,而ArrayDeque是依靠循环数组实现的。
当ArrayDeque满的时候,会进行双倍扩容。
其使用方法和LinkedList大致一样,就不再单独叙述了。

PriorityQueue

优先队列的底层结构是数组,是用数组模拟的满二叉树。

如下图所示,堆分为大顶堆和小顶堆。PriorityQueue的默认为小顶堆。

如果想要实现自定义排序,可以自定义Comparator对象,然后通过构造方法传入就可以了。

PriorityQueue pq = new PriorityQueue(myCmp);

javaArrayList元素的下标_数组_03

常用方法:
add(E e):向堆中加入元素
remove(E e):从堆中移除指定元素
poll():从堆顶弹出并返回元素
peek():获取堆顶元素

3、Set

set也是一个集合,只不过不允许存在重复的元素

javaArrayList元素的下标_java_04


本篇文章,我们主要介绍HashSet、LinkedHashSet和TreeSet。

1、HashSet

从名字就可以看出来,HashSet的底层是涉及到Hash表的。源码中HashSet中是依靠HashMap实现的。

HashMap的实现你们可以参考上一篇文章:第十一篇:Java中Map详解 HashMap、LinkedHashMap、TreeMap、HashMap扩容原理详解

HashSet<Integer> set = new HashSet<>();
set.add(1);

HashSet中内部定义了一个PRESENT常量;
private final Object PRESENT = new Object();
比如set.add(1),是将1作为key,PRESENT作为value,插入map中。

通过HashMap,HashSet能够做到元素不重复。

主要方法:
add(E e):加入元素e
remove(E e):移除元素e
contains(E e):判断是否存在元素e

遍历方式:

1、Iterator

Iterator<String> it = set.iterator();
while (it.hasNext()){
    System.out.println(it.next());
}

2、for循环

for (String s:set){
    System.out.println(s);
}

通过for循环我们可以看出来,HashSet中是没有下标的概念的,无法通过下标来获得数据。HashSet中的元素不是按照元素的插入顺序排列的,而是按照一定的Hash算法来排列的。

2、LinkedHashSet

通过Linked关键词,就大概知道LinkedHashSet和HashSet的大概区别了。
HashSet中的元素遍历输出不是按照元素的插入顺序排列的,而LinkedHashSet是按照元素插入元素排列的。

LinkedHashSet是通过LinkedHashMap来实现的。

LinkedHashMap的实现你们可以参考上一篇文章:第十一篇:Java中Map详解 HashMap、LinkedHashMap、TreeMap、HashMap扩容原理详解

其使用方法和HashSet基本一致。

3、TreeSet
TreeSet是依照TreeMap的原理实现的

TreeMap的实现你们可以参考上一篇文章:第十一篇:Java中Map详解 HashMap、LinkedHashMap、TreeMap、HashMap扩容原理详解

TreeSet和HashSet、LinkedHashSet的区别就是TreeSet中的元素是有序的。

当用户初始化TreeSet的时候,可以传入自定义的Comparator。
如果是自定义对象的TreeSet的话,自定义对象需要实现Comparable接口,要不再put元素的时候会报错。