目录
一、Collection集合
1、Collection集合概述
Collection是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现
方法名 | 说明 |
---|---|
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 从集合中移除指定的元素 |
boolean removeIf(Object o) | 根据条件进行移除 |
void clear() | 清空集合中的元素 |
boolean contains(Object o) | 判断集合中是否存在指定的元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中元素的个数 |
创建Collection集合的对象可使用多态的方式,有具体的实现类ArrayList
2、Collection集合的三种遍历方式
(1)迭代器遍历
java中迭代器是集合专用的遍历方式。
e.g.
public class IteratorDemo1 {
public static void main(String[] args) {
//创建集合对象
Collection<String> c = new ArrayList<>();
//添加元素
c.add("hello");
c.add("world");
c.add("java");
c.add("javaee");
//Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
Iterator<String> it = c.iterator();
//用while循环改进元素的判断和获取
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
}
}
迭代器中的删除
//void remove(): 删除迭代器对象当前指向的元素
public class IteratorDemo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
Iterator<String> it = list.iterator();
while(it.hasNext()){
String s = it.next();
if("b".equals(s)){
//指向谁,那么此时就删除谁.
it.remove();
}
}
System.out.println(list);
}
}
(2)增强for遍历
增强for遍历的内部原理就是一个Iterator迭代器,是为了简化迭代器的代码书写的。
实现Iterable接口的类才可以使用迭代器和增强for。
单列集合和数组才能用增强for遍历。
for(String str : list){
System.out.println(str);
}
细节:修改增强for中的变量不会改变集合中原有的数据。
迭代器遍历完毕,指针不会复位。
循环中只能用一次next方法。
迭代器遍历时,不能用集合的方法进行增加或者删除。
(3)lambda表达式
public static void main(String[] args) {
/*
lambda表达式遍历:
default void forEach(Consumer<? super T> action):
*/
//1.创建集合并添加元素
Collection<String> coll = new ArrayList<>();
coll.add("zhangsan");
coll.add("lisi");
coll.add("wangwu");
//2.利用匿名内部类的形式
//底层原理:
//其实也会自己遍历集合,依次得到每一个元素
//把得到的每一个元素,传递给下面的accept方法
//s依次表示集合中的每一个数据
/* coll.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});*/
//lambda表达式
coll.forEach(s -> System.out.println(s));
}
二、List集合
1、概述与特有方法
有序,存和取的元素顺序一致。
有索引,用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
可重复,与Set集合不同,列表通常允许重复的元素
Collection有的方法List都实现了继承。
List特有方法:
方法名 | 描述 |
---|---|
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
2、List的五种遍历方式
(1)迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = it.next();
System.out.println(str);
}
(2)列表迭代器
ListIterator<String> it = list.listIterator();
while(it.hasNext()){
String str = it.next();
if("bbb".equals(str)){
//qqq
it.add("qqq");
}
}
(3)增强for遍历
for (String s : list) {
System.out.println(s);
}
(4)lambda表达式
list.forEach(s->System.out.println(s) );
(5)普通for循环
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
3、List底层原理
(1)ArrayList
核心步骤:
1. 创建ArrayList对象的时候,底层先创建了一个长度为0的数组。
数组名字:elementDate,定义变量size。
size这个变量有两层含义:
①:元素的个数,也就是集合的长度
②:下一个元素的存入位置
2. 添加元素,添加完毕后,size++
扩容时机一:
3. 当存满时候,会创建一个新的数组,新数组的长度,是原来的1.5倍,也就是长度为15.再把所有的元素,全拷贝到新数组中。如果继续添加数据,这个长度为15的数组也满了,那么下次还会继续扩容,还是1.5倍。
扩容时机二:
4. 如果一次添加多个元素,1.5倍放不下,那么新创建数组的长度以实际为准。
(2)LinkedList
1. 刚开始创建的时候,底层创建了两个变量:一个记录头结点first,一个记录尾结点last,默认为null
2. 添加第一个元素时,底层创建一个结点对象,first和last都记录这个结点的地址值
3. 添加第二个元素时,底层创建一个结点对象,第一个结点会记录第二个结点的地址值,last会记录新结点的地址值
(3)迭代器
* Iterator<E> iterator() :获取一个迭代器对象
* boolean hasNext() :判断当前指向的位置是否有元素
* E next() :获取当前指向的元素并移动指针
三、Set集合
1、Set集合概述
无序,存与取顺序不一致
不重复,可以将重复元素去除
无索引,不能使用普通for循环遍历,也不能通过索引获取元素,没有使用索引的方法
继承自Collection,其功能均可继承使用。
2、HashSet
存取无序
不可以存储重复元素
(1)哈希值
哈希值是根据hashCode方法算出的int类型整数,该方法定义在Objcet类中,默认使用地址值进行计算。一般情况下会将hashcode方法重写,利用对象内部的属性值来计算哈希值。
(2)对象的哈希值
如果没有重写hashCode方法,不同对象计算出的哈希值并不相同,如果重写过hashCode方法,只要属性值相同,不同对象计算出的哈希值也是相同的。
哈希碰撞:有的时候不同属性值或者不同地址值计算出的哈希值也可能一样。
int index = (数组长度 -1) & 哈希值
如果集合中存储的是自定义对象,则必须要重写hashCode和equals方法。
在jdk8以后,当链表长度超过8,数组长度大于等于64时,会自动转换成红黑树。
3、LinkedHashSet
有序、不重复、无索引
LinkedHashSet底层源于哈希表,使用双链表记录和添加。
如果要进行数据去重,先使用HashSet,如果要求又要去重又要存取有序,再使用LinkedHashSet。
4、TreeSet
(1)概述
不重复、无索引、可排序
默认按照由小到大排序
TreeSet底层源于红黑树的数据结构来进行排序,增删改查性能较优。
TreeSet():根据其元素的自然排序进行排序
TreeSet(Comparator comparator) :根据指定的比较器进行排序
对于数值类型(Integer、Double)默认按照从小到大顺序排序。
对于字符字符串类型,按照ASCII码表中的数字升序进行排序。
(2)Comparator
1、使用空参构造创建TreeSet集合。用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
2、自定义的Student类实现Comparable接口。自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
3、重写接口中的compareTo方法。重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
(3)两种比较方式小结
自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序
(4)两种方式中关于返回值的规则
如果返回值为负数,表示当前存入的元素是较小值,存左边
如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
如果返回值为正数,表示当前存入的元素是较大值,存右边
四、总结
1、如果需要集合中元素可重复:使用ArrayList集合,基于数组。
2、如果需要集合中元素可重复,且增删操作明显多余查询:使用LinkedList集合,基于链表。
3、如果需要对集合中元素进行去重:使用HashSet集合,基于哈希表。
4、如果需要对集合中元素进行去重,且需要保证存取顺序:使用LinkedHashSet集合,基于哈希表和双链表,但效率要低于HashSet。
5、如果需要对集合中元素进行排序:使用TreeSet集合,基于红黑树。