概述
集合不能存储基本数据类型,也不能直接存储java对象,存储的都是java对象的内存地址。(或者说是引用)(这儿应该有个图…)
1
List.add(100) // 自动装箱 Integer
不同集合对应不同数据结构
集合分为两大类:单个方式存储元素(超级父接口:java.util.Collection),键值对方式存储元素(超级父接口: java.util.Map)
Collection 集合的继承结构图(这儿因该有两张图)
Map 集合的继承结构图(这儿因该有一张图)
各个类总结:
1 LinkedList:底层是双向链表。
2 Vector:底层是数组,线程安全的,效率较低,使用较少。
3 HashSet:底层是HashMap,放到 HashSet集合中的元素等同于放到HashMap集合key部分了。
4 TreeSet:底层是TreeMap,放到TreeSet,集合中的元素等同于放到TreeMap集合 key部分了。
5 HashMap:底层是哈希表。
6 Hashtable:底层也是哈希表,只不过线程安全的,效率较低,使用较少。
7 properties:是线程安全的,并且key和value只能存储字符串String。
8 TreeMap:底层是二叉树。TreeMap集合的key可以自动按照大小顺序排序。
存储元素的特点:
1 List集合存储元素的特点: 有序可重复
有序:存进去的顺序和取出的顺序相同,每一个元素都有下标。可重复:存进去1,可以再存储一个1.2 Set集合存储元素的特点: 无序不可重复
无序:存进去的顺序和取出的顺序不一定相同。另外 set集合中元素没有下标。不可重复:存进去1,不能再存储1了。3 SortedSet集合存储元素特点:首先是无序不可重复的,但是SortedSet集合中的元素是可排序的。
无序:存进去的顺序和取出的顺序不一定相同。另外set集合中元素没有下标。
不可重复:存进去1,不能再存储1了。
可排序:可以按照大小顺序排列4 Map集合的 key,就是一个set集合,往set集合中放数据,实际上放到了Map集合的key部分。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52import java.util.*;
public class _513_迭代器是通用的 {
public static void main(String[] args) {
Collection c1 = new ArrayList();
Collection c2 = new HashSet();
Collection c3 = new TreeSet();
c1.add(1);
c1.add(2);
c1.add(3);
c1.add(1);
for (Iterator it = c1.iterator(); it.hasNext(); ){
System.out.println(it.next());
}
/*
1
2
3
1
*/
System.out.println("==================");
c2.add(1);
c2.add(2);
c2.add(3);
c2.add(1); // 这个无效 因为HashSet无序不可重复
for (Iterator it = c2.iterator(); it.hasNext(); ){
System.out.println(it.next());
}
/*
1
2
3
*/
System.out.println(" ============ ");
c3.add(1);
c3.add(3);
c3.add(2);
c3.add(1);
for (Iterator it = c3.iterator(); it.hasNext(); ){
System.out.println(it.next());
}
/*
1
2
3
*/
}
}集合只要发生改变,比如add或remove了某些引用,迭代器必须重新获取,以用来遍历集合
Collection接口中常用方法
- Collection中能存放什么元素?
没有使用“泛型之前,collection中可以存储object的所有子类型。使用了“泛型之后,collection中只能存储某个具体的类型。只要是object的子类型就行。(集合中不能直接存储基本数据类型,也不能存java对象,只是存储java对象的内存地址。)
boolean add(E e);
1 | import java.util.ArrayList; |
int size();
1 | import java.util.ArrayList; |
void clear();
1 | import java.util.ArrayList; |
boolean contains(Object o);
contains使用
1 | import java.util.ArrayList; |
contains解析
这儿应该有张图…
1 | import java.util.ArrayList; |
boolean remove(Object o);
remove方法使用
1 | import java.util.ArrayList; |
remove方法解析
1 | import java.util.ArrayList; |
boolean isEmpty();
1 | import java.util.ArrayList; |
Object[] toArray();
1 | import java.util.ArrayList; |
public interface Iterator{}
执行原理(这儿应该有一张图…)
1 | import java.io.ObjectInput; |
List接口特有方法
void add(int index, E element);
1 | import java.util.ArrayList; |
E get(int index);
1 | import java.util.ArrayList; |
int indexOf(Object o);
1 | import java.util.ArrayList; |
int lastIndexOf(Object o);
1 | import java.util.ArrayList; |
E set(int index, E element);
1 | import java.util.ArrayList; |
ArrayList
- 初始化容量为10,底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量10
- size() 是元素个数,不是容量大小
- 容量满了之后,增长容量grow()变为1.5倍
- 线程不安全的
另一个构造方法 public ArrayList(Collection<? extends E> c) {}
1 | import java.util.ArrayList; |
如何转化为线程安全的
1 | import java.util.ArrayList; |
LinkedList
- 底部是双向链表
- 检索效率低,增删效率高
- 存储内存地址不连续
- 线程不安全的
public E get(int index)
1 | import java.util.LinkedList; |
public boolean add(E e)
1 | import java.util.LinkedList; |
Vector
- 底层是个数组
- 初始化容量为10
- 当容量满了后,调用grow(),扩容为原来的2倍
- 线程安全的,效率较低,使用较少
public synchronized boolean add(E e)
1 | import java.util.Vector; |
泛型机制
- JDK5.0推出的新特性
- 泛型这种语法机制,只在程序编译阶段起作用,只是给编译器参考的。(运行阶段泛型没用!)
- JDK8之后引入了:自动类型推断机制。(又称为钻石表达式)
指定存储Animal类
1 | import java.util.ArrayList; |
自动类型推断机制
1 | import java.util.ArrayList; |
自定义泛型
1 | public class _532_自定义泛型 { |
foreach
- JDK5.0推出新特性 foreach
1 | public class _533_foreach { |
1 | import java.util.ArrayList; |
Set
HashSet
1 | import java.util.HashSet; |
TreeSet
1 | import java.util.Set; |
Map接口常用方法
V put(K key, V value);
1 | import java.util.HashMap; |
V get(Object key);
1 | import java.util.HashMap; |
void clear();
1 | import java.util.HashMap; |
int size();
1 | import java.util.HashMap; |
boolean containsKey(Object key);
1 | import java.util.HashMap; |
boolean containsValue(Object value);
1 | import java.util.HashMap; |
boolean isEmpty();
1 | import java.util.HashMap; |
Collection values();
1 | import java.util.Collection; |
Set keySet();
1 | import java.util.HashMap; |
Set<Map.Entry<K, V>> entrySet();
1 | import java.util.HashMap; |
HashMap
- HashMap集合底层是哈希表/散列表的数据结构。
- 哈希表是一个怎样的数据结构呢?
哈希表是一个数组和单向链表的结合体。
数组∶在查询方面效率很高,随机增删方面效率很低。
单向链表:在随机增删方面效率较高,在查询方面效率很低。
哈希表将以上的两种数据结构融合在―起,充分发挥它们各自的优点。 - HashMap集合底层的源代码:
1
2
3
4
5
6
7
8
9
10
11
12public class HashMap {
// HashMap底层实际上就是一个数组。(一维数组)
node<K, V>[] table;
//静态的内部类HashNap.Node
static class Node<K, V> {
final int hash; //哈希值是key 的hashCode()方法的执行结果。
final K key; //存储到Map集合中的那个key
V value; //存储到Map集合中的那个value
Node<K, V> next; //下一个节点的内存地址。
}
} - 哈希表数据结构:
(这儿应该有张图…) - HashMap集合的默认初始化容量是16,默认加载因子是0.75
这个默认加载因子是当HashMap集合底层数组的容量达到75%的时候,数组开始扩容。
重点: 记住: HashMap集合初始化容量必须是2的幂次,这也是官方推荐的,这是因为达到散列均匀,为了提高HashMap集合的存取效率,所必须的。 - 重写hashCode()和equals()通过IDEA要两者同时重写,IDEA自动生成
- 放在HashMap集合key部分的,以及放在HashSet集合中的元素,需要同时重写hashCode方法和equals方法。
- HashMap在JDK8之后
如果哈希表单向链表中元素超过8个,单向链表这种数据结构会变成红黑树数据结构
当红黑树上的节点数里小于6时,会重新把红黑树变成单向链表数据结构
同时重写hashCode和equals
1 | import java.util.HashSet; |
HashMap和Hashtable的区别
- HashMap和Hashtable一样底层都是哈希表
- Hashtable初始化容量11,默认加载因子是0.75
- Hashtable 的 key 和 value 都不能为 null
- Hashtable 扩容是原容量 * 2 + 1
Hashtable 的 key 和 value 都不能为 null
1 | import java.util.HashMap; |
Properties
- key 和 value 用于存 String
getProperty() 和 setProperty()
1 | import java.util.Properties; |
TreeSet
- TreeSet集合底层实际上是一个TreeMap
- TreeMap集合底层是一个二叉树。
- 放到TreeSet集合中的元素,等同于放到TreeMap集合key部分了。
- TreeSet集合中的元素:无序不可重复,但是可以按照元素的大小顺序自动排序。称为:可排序集合。
TreeSet对String是可排序的
1 | import java.util.TreeSet; |
自定义类型实现Comparable接口
1 | import java.util.TreeSet; |
1 | import java.util.TreeSet; |
实现比较器接口
1 | import java.util.Comparator; |
Collections工具类
- java.util.collection 集合接口
- java.util.collections 集合工具类,方便集合的操作。
Collections.synchronizedList()
1 | import java.util.ArrayList; |
Collections.sort()
1 | import java.util.ArrayList; |