我宁愿写bug⚠️,也不愿什么都不做 ❗️
💚哈喽!大家好!💚
❤️我是 一看就会,一写就废 的 浩浩🔍❤️
💙让我带你编程带你飞,带你飞进垃圾堆!💙
💜 如果对你有所帮助,请给我点个赞👍!💜
键盘敲烂💥,工资过万💰
一、 集合类介绍
1.1 为什么出现集合类
面向对象语言是对事物的体现都是以对象的形式,为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式
1.2 数组和集合的区别
- 数组和集合类都是容器。
- 数组声明了它容纳的元素的类型,而集合不声明。
- 数组长度是固定的;集合长度是可变的。
数组是静态的,一个数组实例具有固定的大小,一旦创建了就无法改变容量了。而集合是可以动态扩展容量,可以根据需要动态改变大小,集合提供更多的成员方法,能满足更多的需求。
- 数组中可以存储基本数据类型和引用数据类型,集合只能存储对象。
数组的存放的类型只能是一种(基本类型/引用类型),集合存放的类型可以不是一种(不加泛型时添加的类型是Object)。
- 数组中存储数据类型是单一的,集合中可以存储任意类型的对象。
- 数组是java语言中内置的数据类型,是线性排列的,执行效率或者类型检查都是最快的。
1.3 集合类图
-
Collection:所有集合类的根接口
-
Map:映射接口,存放键值对
-
Iterator:遍历集合的迭代接口
二、 Collection接口与Iterator接口
2.1 Collection接口
- Collection接口位置 java.util.Collection
- Collection接口有三个子接口。Collection 接口是 List、Set 和 Queue 接口的父接口,通常情况下不被直接使用。
- List(列表) ,Set(集)、Queue(队列)
List:元素存取是有序的,可存放重复元素。元素都有下标
Set:元素存取是无序的,不可以存放重复元素。元素没有下标,元素不可以重复
Queue:队列,实现了先进先出
2.1.1 Collection接口的常用方法
方法 | 说明 |
---|---|
boolean add(Object o) | 向集合中加入指定对象o,增加成功返回true,失败false |
boolean addAll(Collection c) | 将指定集合c内的所有元素添加到该集合内,增加成功返回true,否则返回false |
void clear() | 删除集合内的所有元素 |
boolean contains(Object o) | 判定集合内是否包含指定元素,是返回true |
boolean containsAll(Collection c) | 判定集合内是否包含集合c的所有元素 ,是返回true |
boolean isEmpty() | 判定是否为空集合,是返回true |
Iterator iterator() | 返回一个Iterator对象,可以用来遍历集合中的元素 |
boolean remove(Object o) | 从集合中删除指定元素 o,成功则返回true |
boolean removeAll(Collection c) | 删除该集合中包含集合c的所有元素,若删除了1个及以上的元素则返回true |
boolean retainAll(Collection c) | 删除该集合中除集合c中元素以外的元素,若调用该方法的集合元素改变了,则返回true |
int size() | 返回集合中元素的数目 |
Object[] toArray() | 返回一个数组,该数组中包括集合中的所有元素 |
2.2 Iterator接口
2.2.1 Iterator接口的作用
如果要遍历集合中的元素,在学数组时我们常用for循环遍历数组中的元素,在集合中也可使用传统循环方法实现,此外,集合中也可以使用到Iterator对象来遍历集合的数组,此方法更简单。
Iterator通过遍历(迭代访问)集合中的元素来获取或删除某元素,仅用于遍历集合,可以应用于Set、List、Map以及其子类,Iterator对象也被称为迭代器。
ListIterator在Iterator基础上进行了扩展,允许双向遍历列表,而Iterator只能向后迭代,但ListIterator只能用于List及其子类。
2.2.2 Iterator接口的常用方法
方法 | 接口类型 | 说明 |
---|---|---|
boolean hasNext() | Iterator | 还有元素可以迭代返回true |
Object next() | Iterator | 返回下一个元素 |
void remove() | Iterator | 删除当前元素 |
void add(Object o) | ListIterator | 将指定元素o插入集合,该元素在下一次调用next()方法时被返回 |
boolean hasNext() | ListIterator | 存在下一个元素时返回true |
boolean hasPrevious() | ListIterator | 存在前一个元素时返回true |
Object next() | ListIterator | 返回列表中的下一个元素 |
Object previous() | ListIterator | 返回列表中的前一个元素 |
int nextIndex() | ListIterator | 返回列表下一个元素的下标,如果不存在下一个元素,则返回列表的大小 |
int previousIndex() | ListIterator | 返回列表前一个元素的下标,如果不存在前一个元素,则返回 -1 |
void remove() | ListIterator | 删除当前元素 |
void set(Object o) | ListIterator | 将o赋值给当前元素,即上一次调用next方法或previous方法后返回的元素 |
三、 List 集合
3.1 List 接口的特点
- List集合为单列集合。
- 元素有序(按照元素的插入顺序保存元素),元素可重复。
- 有索引,可通过索引对元素进行操作。
3.1.1 List 实现类的特点
- ArrayList
- 底层数据结构是数组,查询快,增删慢。
- 线程不安全,效率高
- 初始容量为10,扩容1.5倍
- LinkedList
- 底层数据结构是链表,查询慢,增删快。
- 线程不安全,效率高。
- Vector
- 底层数据结构是数组。
- 线程安全,效率低,现已经被ArrayList替代。
- 初始容量为10,扩容2倍
- Stack 栈
- 底层调用Vector类中的方法,数组实现。
- 先进后出。
3.2 List 接口的常用方法
方法 | 说明 |
---|---|
boolean add(int index, Object element) | index为对象element要加入的位置,其他对象的索引位置相对后移1位,索引位置从0开始 |
E remove(int index) | 移出列表中指定位置元素 |
E set(int index, E element) | 用指定元素替换列表中指定位置元素 |
E get(int index) | 返回列表中指定位置元素 |
int indexOf(Object o) | 返回列表中指定元素位置的索引。存在多个时,返回第一个的索引位置,不存在返回-1 |
int lastIndexOf(Object o) | 返回列表中指定元素位置的索引。存在多个时,返回最后一个的索引位置,不存在返回-1 |
ListIterator<> listIterator() | 返回此列表元素的列表迭代器(按适当顺序) |
ListIterator<> listIterator(int index) | 返回此列表元素的列表迭代器(按适当顺序),从列表的指定位置开始 |
List <> subList(int fromIndex, int toIndex) | 返回一个指定区域的List集合对象,指定区域从索引fromIndex(包括)到索引toIndex(不包括) |
从表中可以看出,List接口提供的适合于自身的常用方法均与索引有关,这是因为List集合为列表类型,以线性方式存储对象,可以通过对象的索引操作对象。
List接口的常用实现类有ArrayList和LinkedList,在使用List集合时,通常情况下声明为List类型,实例化时根据实际情况的需要,实例化为ArrayList或LinkedList,例如:
// 利用ArrayList类实例化List集合
List<String> list = new ArrayList<>();
// 利用LinkedList类实例化List集合
List<String> lsit2 = new LinkedList<>();
3.3 ArrayList
3.3.1 ArrayList 常用方法
- 增:add(o) add(index,o)
- 删:remove(o) remove(index)
- 改:set(index,o)
- 查:
-
单查:get(index)
-
查所有:循环遍历
1.for循环for(int i=0;i<list.size();i++){ get(i); }
2.迭代器
Iterator it = list.iterator(); while(it.hasNext()){ Integer a = (Integer)it.next(); }
3.for增强循环
for(Integer i:list){ i }
-
3.4 LinkedList
3.4.1 LinkedList 类的常用方法
方法 | 说明 |
---|---|
void addFirst(E e) | 将指定元素插入此列表的开头 |
void addLast(E e) | 将指定元素插入此列表的结尾 |
E getFirst() | 返回列表开头的元素 |
E getLast() | 返回列表结尾的元素 |
E removeFirst() | 移除列表开头的元素 |
E removeLast() | 移除列表结尾的元素 |
3. Stack 栈
- new Stack() 初始化
- push(o) 添加元素
- pop() 移出栈定元素
- peek() 查栈顶元素
四、 Set 集合
4.1 Set 接口的特点
- 单列集合
- 无序、元素不能重复、
- 无索引
4.1.1 Set 实现类的特点
- HashSet
- 底层数据结构是哈希表,存取速度快
- 线程不安全
- 元素无序,可以为null
- LinkedHashSet(HashSet的子类)
- 哈希表和链表实现了Set接口
- 元素有序(按照元素的插入顺序保存元素)
- TreeSet
- 底层数据结构是红黑树,默认整形排序为从小到大
- 存储的对象此项实现Comparable接口
- 线程不安全
- 元素可以为null
4.2 HashSet
4.2.1 HashSet 特点
- HashSet:无序不重复,无索引
- 默认不重复的是虚地址,要想内容不重复,就重写hashcode和equals方法。
- 底层是HashMap实现,HashMap底层是由数组+链表+红黑树实现
- HashSet堪称查询速度最快的集合,因为其内部是以HashCode来实现的。它内部元素的顺序是由哈希码来决定的,所以它不保证set的迭代顺序;特别是它不保证该顺序恒久不变
- 无索引,无法使用for循环来遍历,可以使用增强for循环和迭代器来循环
- 造成存泄露的原因:HashSet的remove方法也依赖于哈希值进行待删除节点定位,如果由于集合元素内容被修改而导致hashCode方法的返回值发生变更,那么,remove方法就无法定位到原来的对象,导致删除不成功,从而导致内存泄露。
4.2.2 判断重复的方法:
HashSet 判断重复元素是根据元素的 hashCode()的值是否相等,如果不相等,则不用再去执行 equals()方法,两个对象不相等。如果 hashCode()的值相等,需要去执行元素的 equal()方法,如果返回 true 代表像个对象相等,否则两个对象不相等。比较的次数是元素的个数-1.。
4.2.3 HashSet 常用方法
-
增:add(o)
-
删:remove(o) 删除指定元素 clear() 移除集合中所有的元素
-
改:先删除,再添加
-
查:
1.for增强循环for(Integer i:set){ i }
2.迭代器
Iterator it=set.iterator(); while(it.hasNext()){ Integer a=(Integer)it.next(); }
4.3 TreeSet
4.3.1 TreeSet 特点
无序不重复,但是排序。 线程不安全(不同步)。底层基于TreeMap 实现。
4.3.2 排序比较的方法
TreeSet 是处于排序状态的 Set,他的排序是根据元素的内部比较器(元素类本身实现了 Comparable 接口,重写 ComparaTo 方法)或者外部比较器(专门写一个新类,让这个新类实现Comparator 接口,重写 Compare()方法,进行比较。TreeSet 实例使用它的 compareTo(或compare)方法对所有元素进行比较。比较的次数是元素的个数-1。
1.自然排序
public static void main(String[] args) {
TreeSet<String> set = new TreeSet<>();
//增
set.add("b");
set.add("a");
set.add("c");
set.add("aa");
set.add("cc");
set.add("bb");
//输出
System.out.println(set);//按照元素的自然排序输出
}
2.自定义类
1.内部比较器
1.类实现Comparable接口,重写compareTo()方法
public class Person implements Comparable<Person> {
private String name;
private int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Person o) {
//比较规则:1.name 2:age
//1.name
int i = this.name.compareTo(o.name);
return i==0?this.age-o.age:i;
}
}
2.测试方法
public static void main(String[] args) {
//创建TreeSet
TreeSet<Person> set = new TreeSet<>();
//创建person对象
Person person1 = new Person("tom", 29);
Person person2 = new Person("tom", 28);
Person person3 = new Person("jim", 38);
//放入set
set.add(person1);
set.add(person2);
set.add(person3);
System.out.println(set);
}
2.外部比较器
1.类不实现Comparable接口
2.测试类创建TreeSet使用Comparator有参构造方法
public static void main(String[] args) {
//创建TreeSet对象,指定外部比较器
TreeSet<Person> set = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int i = o1.getName().compareTo(o2.getName());
return i==0?o1.getAge()-o2.getAge():i;
}
});
//创建person对象
Person person1 = new Person("tom", 29);
Person person2 = new Person("tom", 28);
Person person3 = new Person("jim", 38);
//放入set
set.add(person1);
set.add(person2);
set.add(person3);
System.out.println(set);
}
五、 Map 集合
5.1 Map接口的特点
Map集合用于保存具有映射关系的数据,在Map集合中保存着两组值,一组值是key键,另一组值是value值。key和value之间存在一对一的关系,通过指定的key键就能找到唯一的value值。Map中的key键不允许重复(key键唯一),value值可以重复
5.1.1 Map实现类的特点
- HashMap
线程不安全,速度快,允许存放null键,null值。
- LinkedHashMap
继承自HashMap,它主要是用链表实现来扩展HashMap类
- HashTable
线程安全,速度慢,不允许存放null键,null值,已被HashMap替代。
- ConcurrentHashMap
线程安全并且高效的HashMap
- TreeMap
对键进行排序,排序原理与TreeSet相同
5.2 Map 接口常用方法
方法 | 说明 |
---|---|
put(K key, V value) | put(K key, V value) |
void putAll(Map<? extends K, ? extends V> m) | 向集合中添加指定集合中所有的键——值映射关系 |
boolean containsKey(Object key) | 判断此集合中是否包含指定的键映射关系 |
boolean containsValue(Object value) | 判断此集合中是否包含指定的值映射关系 |
V get(Object key) | 返回指定的键所映射的值,否则返回null |
Set keySet() | 以Set集合的形式返回该集合中的所有键对象 |
Collection values() | 以Collection集合的形式返回该集合中的所有值对象 |
V remove(Object key) | 删除并返回键对应的值对象 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 返回集合中键——值映射关系的个数 |
boolean equals(Object o) | 比较指定的键——值映射关系是否相等 |
void clear() | 清空集合中所有的映射关系 |
5.3 HashMap
5.2.1 HashMap 特点
- 底层实现1.7之前:数组+链表 1.8以后:数组+链表+红黑树
- key不允许重复,如果key的值相同,后添加的数据会覆盖之前的数据
- HashMap是非线程安全的
5.4 TreeMap
5.4.1 TreeMap 特点
- TreeMap基于红黑树数据结构的实现
- 键可以使用Comparable或Comparator接口, 重写compareTo方法来排序。
- 自定义的类必须实现接口和重写方法,否则抛异
- Key值不允许重复,如果重复会把原有的value值覆盖。
5.4.2 排序方法
1.基于JDK写好的实现了Comparable接口的实体类对象排序例如String
public static void main(String[] args) {
//创建TreeMap对象
TreeMap<String, String> map = new TreeMap<>();
//增
map.put("b", "b的value");
map.put("a", "a的value");
map.put("cc", "cc的value");
map.put("c", "c的value");
System.out.println("map = " + map);
}
2.自定义类是实现Comparable接口的内部比较器
- 自定义实现Comparable接口,重写compareTo(Object o){}
import java.util.TreeMap;
public class TestPerson {
public static void main(String[] args) {
//创建TreeMap对象
TreeMap<Person, String> map = new TreeMap<>();
//增
map.put(new Person("王东阳", 20), "小男神");
map.put(new Person("李浩", 20), "小帅哥");
map.put(new Person("范菲菲", 19), "小美女");
//输出
System.out.println(map);
}
}
-
外部比较器
Person不实现Comparable接口,在TreeMap的构造方法实现
import java.util.Comparator;
import java.util.TreeMap;
import java.util.TreeSet;
public class TestPerson {
public static void main(String[] args) {
//创建TreeMap对象
TreeMap<Person, String> map = new TreeMap<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int i = o1.getAge() - o2.getAge();
return i==0?o1.getName().compareTo(o2.getName()):i;
}
});
//增
map.put(new Person("王东阳", 20), "小男神");
map.put(new Person("李浩", 20), "小帅哥");
map.put(new Person("范菲菲", 19), "小美女");
//输出
System.out.println(map);
}
}
5.4.23遍历TreeMap集合的方法
-
TreeSet
public static void main(String[] args) { //创建TreeMap对象 TreeMap<String, String> map = new TreeMap<>(); //增 map.put("b", "b的value"); map.put("a", "a的value"); map.put("cc", "cc的value"); map.put("c", "c的value"); //1.keySet Set<String> keySet = map.keySet(); for (String key : keySet) { System.out.println(key+":"+map.get(key)); } System.out.println("-----------------------"); //iterator Iterator<String> iterator = keySet.iterator(); while (iterator.hasNext()){ String key = iterator.next(); System.out.println(key+":"+map.get(key)); } }
-
EntrySet
public static void main(String[] args) { //创建TreeMap对象 TreeMap<String, String> map = new TreeMap<>(); //增 map.put("b", "b的value"); map.put("a", "a的value"); map.put("cc", "cc的value"); map.put("c", "c的value"); //2.entrySet Set<Map.Entry<String, String>> entrySet = map.entrySet(); for (Map.Entry<String, String> entry : entrySet) { System.out.println(entry.getKey()+":"+entry.getValue()); } System.out.println("-------------------"); Iterator<Map.Entry<String, String>> iterator = entrySet.iterator(); while (iterator.hasNext()){ Map.Entry<String, String> entry = iterator.next(); System.out.println(entry.getKey()+"="+entry.getValue()); } }
5.5 HashTable
5.5.1 HashTable 特点
- 和Vector类似,Map体系也有一个自JDK1.2之前遗留的集合工具:Hashtable
- HashTable和HashMap的区别在于:
- HashTable是线程安全的,而HashMap是非线程安全的
- HashTable不允许空的键值对,而HashMap可以
- HashTable与HashMap都实现Map接口,但二个类的继承的父类不是同一个
- HashTable底层实现:数组+链表+红黑树
- 常用方法:同HashMap方法
5.6 ConcurrentHashMap
5.6.1 ConcurrentHashMap 特点
-
ConcurrentHashMap是线程安全并且高效的HashMap
-
常用方法:同HashMap
-
数据结构:JDK8 数组+链表+红黑树,数据结构可能是链表,也可能是红黑树,红黑树是为了提高查找效率。采用CAS+Synchronized保证线程安全。
六、 总结各集合类之间的对比
Arraylist | LinkedList | HashSet | TreeSet | HashMap | TreeMap | |
---|---|---|---|---|---|---|
是 否 有 序 | 有序 | 有序 | 无序 | 有序 | 无序 | 有序 |
存 储 结 构 | 集合 | 集合 | 集合 | 集合 | 键值对 | 键值对 |
线 程 安 全 | 否 | 否 | 否 | 否 | 否 | 否 |
元 素 是 否 有 重 复 | 是 | 是 | 否 | 否 | 键值唯一 相同覆盖 | 键值唯一 相同覆盖 |
元 素 是 否 可 为 null | 是 | 是 | 是 | 是 | key是 value是 | key否 value是 |
底 层 数 据 结 构 | 数组 | 链表 | 哈希表 | 二叉树 | 哈希表 | 红黑树 |
特 点 | 查询快,增删慢 | 查询慢,增删快 | 快速查找 | 快速排序 | 插入、删除和定位元素快 | 按自然顺序或自定义顺序遍历快 |
Map集合是否能存放null值总结
集合类 | key | value | super | 说明 |
---|---|---|---|---|
HashTable | 不能为null | 不能为null | Dictionary | 线程安全 |
ConcurrentHashMap | 不能为null | 不能为null | AbstractMap | 线程局部安全 |
TreeMap | 不能为null | 可以为null | AbstractMap | 线程不安全 |
HashMap | 可以为null | 可以为null | AbstractMap | 线程不安全 |