1.数组就是一个集合
2.集合实际上就是一个容器,可以容纳其他类型的数据
3.集合是一个容器,是一个载体,可以一次容纳多个对象
4.集合当中不能直接存储基本数据类型,另外集合也不能直接存储java对象,集合当中存储的是java对象的内存地址【引用】
5.集合本身是一个容器,是一个对象,集合中任何时候存储的都是引用
6.在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合当中存储元素,等于将数据放到了不同的数据结构当中
7.数据存储的结构就是数据结构。不同的数据结构,数据的存储方式不同。例如:
数组
二叉树
链表
哈希表
8.java已经将数据结构实现了,已经写好了这些常有的集合类。
new ArrayList();创建一个集合对象,底层是数组
new Linkedlist();创建一个集合对象,底层是链表
new TreeSet();创建一个集合对象,底层是二叉数
9.所有的集合类和集合接口都在java.util包下
10.在java中集合分为两大类:
- 一类是以单个方式存储元素:
- 单个方式存储元素,这一类集合中集合超级父接口:java.util.Collection;
- 一类是以键值对的方式存储元素
- 以键值对的方式尊出元素,这一类集合中超级父接口:java.util.Map;
11.Iterator it = "Collection 对象".iterator();
it是迭代器对象
12.
ArrayList:底层是数组
LinkedList:底层是双向链表
Vector:底层是数组,线程安全,效率较低,使用较少
HashSet:底层是HashMap,放到HashSet集合中的元素等同于放到HashMap集合key部分了
TreeSet:底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合key部分了
HashMap:底层是哈希表
Hashtable:底层也是哈希表,只不过线程安全,效率较低,使用较少
Properties:是线程安全的,并且key和value只能存储字符串String
TreeMap:底层是二叉树。TreeMap集合的key可以自动按照大小顺序排序
List集合存储元素的特点:
有序可重复
有序:存进去的顺序和取出来的顺序相同,每一个元素都有下标
可重复:可以存进去一个1,在存进去一个1
Set(Map)集合存储元素的特点
无序不可重复
无序:存进去的顺序和取出来的顺序不一定相同。另外Set集合中元素没有下标
不可重复:存进去1,不能再存1了
SortedSet(SortedMap)集合存储元素的特点:
首先是无序不可重复的,但是SortedSet集合中的元素是可排序的
无序:存进去的顺序和取出来的顺序不一定相同。另外Set集合中元素没有下标
不可重复:存进去1,不能再存1了
可排序:可以按照大小顺序排序
Map集合的key,就是一个Set集合
再Set集合中放数据,实际上放到了Map集合当中的key部分了
13.
14.
15.关于java.util.Collection接口中常用的方法
1.没有使用泛型之前,Collection中可以存储Object中所有的子类型。使用了泛型之后,Collextion中只能存储某个的类型
2.Collection中什么都可以存,只要是Object的子类就行(集合中不能直接存储基本数据类型,也不能存java对象,只能存储java对象的内存地址)
16.Collection中的常用方法
1.boolean add(Object e) 向集合中添加元素
2.int
size() 获取元素的个数
3.void clear() 移除此 collection 中的所有元素
4.boolean contains(Object o) 如果此 collection 包含指定的元素,则返回 true。
5.boolean remove(Object o) 从此 collection 中移除指定元素的单个实例,如果存在的话
6.boolean isEmpty() 如果此 collection 不包含元素,则返回 true。
7.Object[] toArray() 返回包含此 collection 中所有元素的数组。
17.对集合Collection进行迭代
1.获取集合对象的迭代器对象
Iterator it = c.iterator();2.迭代器中的方法:
boolean hasNext() 如果仍有元素可以迭代,则返回 true。Object next() 返回迭代的下一个元素。3.
Iterator it = c.iterator(); while (it.hasNext()){ Object o = it.next(); System.out.println(o); }
18.存放在集合中的元素需要重写equals方法
19.获取的迭代对象,迭代器用来遍历集合,此时相当于对当前集合的状态进行了一个快照。迭代器迭代的时候会参照这个快照进行迭代
20.List的特有的,常用的方法:
1.
void add(int index, Object object) 在列表的指定位置插入指定元素(可选操作)。2.
Object get(int index) 返回列表中指定位置的元素。3.
int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。4.
int lastIndexOf(Object o) 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。5.
Object remove(int index) 移除列表中指定位置的元素6.
Object set(int index, Object object) 用指定元素替换列表中指定位置的元素
21.ArrayList集合
1.默认初始化容量10,(底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量10)
2.集合底层是一个Object[]数组
3.构造方法:
new ArrayList();
new ArrayList(20);
4.ArrayList的扩容:扩容到原容量的1.5倍
尽可能少的扩容,建议再使用ArrayList集合的时候预估元素的个数,给定一个初始化容量
5.优点:检索效率比较高 (每个元素占用空间大小相同,内存地址是连续的,知道首元素内存地址,然后知道下标,通过数学表达式计算出元素的内存地址,所以检索效率最高)
6.缺点:随机增删元素效率比较低
另外数组无法存储大数据量
7.向数组末尾增删元素,效率很高,不受影响
22.链表:
1.对于链表来说,任何一个节点Node中都有两个属性:
第一:存储的数据
第二:下一节点的内存地址
2.优点:随机增删元素效率较高。(因为增删元素不涉及到大量元素位移)
3.缺点:查询效率较低,每一次查找某个元素的时候都需要从头节点开始往下遍历
23.泛型
1.jdk5.0之后推出新特性:泛型
2.泛型这种语法机制,只在程序编译阶段起作用,只是给编译参考的,(运行阶段泛型没用)
3.泛型的好处
1.集合中存储的元素类型统一了
2.从集合中取出的元素类型是泛型指定的类型,不需要进行大量的向下转型
4.泛型的缺点
导致集合中存储的元素缺乏多样性
大多数业务类型中,集合中元素的类型还是统一的
5.泛型可以自定义
自定义泛型的时候,<>尖括号中的只是一个字符串,可以随便写
java源代码中经常出现的是:<E>,<T>
E是Element单词首字母
T是Type单词首字母
24.jdk8之后引入了:自动类型推断机制(又称钻石表达式)
25.jdk5.0之后退出了一个新特新:叫做增强for循环,或者foreach
1.for(元素类型 变量名 : 数组或集合){
}
2.缺点:没有下标,在需要使用下标的循环中不建议使用增强for循环
26.Map集合以key和value的方式存储数据:键值对
key和value都是引用数据类型
key和value都是存储对象的内存
key起到主导的地位,value是key的一个附属品
27.Map接口中常用的方法
V put(K key, V value) 向Map集合中添加键值对
V get(Object key) 清空key获取value
void clear() 清空Map集合
boolean containsKey(Object key) 判断Map中是否包含某个value
boolean containsValue(Object value) 判断Map中是否包含某个value
boolean isEmpty() 判断Map集合中元素个数是否为0
Set<k> keySet() 获取Map集合所有的key(所有的键是一个set集合)
V remove(Object key) 通过key删除键值对
int size() 获取Map集合中的键值对的个数
Collection<V> values() 获取Map集合中所有的value,返回一个Collection
Set<Map.EnTry<K,V>> entrySet() 将Map集合转换成Set集合
Map集合通过entrySet()方法转换成的这个Set集合,Set集合元素的类型是Map.Entry<K,V>
Map.Entry和String一样,都是一种类型的名字,只不过:Map.Entry是静态内部类,是Map中的静态内部类
28.map.put(k,v)实现原理
第一步:先将k,v封装到Node对象当中
第二步:底层调用k的hashCode()方法得出hash值,然后通过哈希函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上了。如果说下标对应的位置上有链表,此时会拿着k和链表上每一个节点中的k进行equals,如所有的equals方法都返回false,那么这个新节点将被添加到链表的末尾。如果其中有一个equals但会了true,那么这个节点的value将会被覆盖
29.v = map.get(k)实现原理:
先调用k的hashCode()方法得出哈希值,通过哈希算法转换成数组下标,通过数组下标快速定位到某个位置上,如果这个位置上什么也没有,返回null。如果这个位置上有单向链表,那么会拿着参数k和单向链表上的每个节点中的k进行equals,如果所有equals方法返回false,那么get方法返回null,只要其中有一个节点的k和参数k equals的时候返回true那么此时这个节点的value就是我们要找的value,get方法最终返回这个要找地value
30.为什么哈希表地随机增删,以及查询效率都很高
增删是在链表中完成,查询也不需要扫描,只需要部分扫描
31.HashMap集合的k会先后调用亮哥方法,一个是hashCode(),一个方法是equals(),那么这两个方法都需要重写
32.HashMap集合存放元素的特点:无序不可重复
为什么无序,因为不一定挂到哪个单向链表上
怎么保证不重复,equals方法来保证HashMap集合的key不可重复。如果key重复了,value会覆盖
33.同一个单链表上所有节点的hash相同,因为他们的数组下标是一样的。但是同一个链表上的k和k的equals方法肯定返回false,都不相等
34.放到HashMap集合key部分的元素其实就是放到HashSet集合中了,所以HashSet集合中的元素也需要同时重写hashCode()+equals()方法
35.哈希表HashMap使用不当时无法发挥性能
假设将所有的hashCode()方法返回值固定为某个值,那么会导致底层哈希表变成纯单向链表,这种分布我们称为散列分布不均匀
散列分不均匀:假设有100个元素,10个单向链表,那么每个单向链表上有10个节点,这是最好的,是散列分布均匀的。
36.放在HashMap集合key部分的元素以及放在HashSet集合中的元素,需要同时重写hashCode()和eqauls()方法
37.HashMap集合的默认初始化容量是16,默认加载因子是0.75
默认加载因子是当HashMap集合底层数组的容量达到75%的时候,数组进行扩容
38.HashMap集合初始化容量必须是2的倍数,这也是官方推荐的,这是因为达到散列表均匀,为了提高HashMap集合的存取效率,所必须的
39.如果一个类的equals方法重写了,那么hashCode()方法必须重写,并且equals方法返回如果是true,hashCode()方法返回的值必须一样。
40.equals方法返回true表示两个对象相同,在同一个单向列表上比较。那么对于同一个单向链表上的节点来说,他们的哈希值都是相同的。所以hashCode()方法的返回值也应该相同
41.在jdk8之后,如果哈希表单向链表中元素超过8个,单向链表这种数据结构会变成红黑树数据结构。当红黑树上的节点数量小于6是,会重新把红黑树变成单向链表数据结构
42.HashMap集合key部分允许null,但是HashMap集合的key部分null值只能有一个
43.Hashtable的key和value不允许为null,Hashtable集合初始化容量为11,Hashtable集合扩容是:原容量*2+1
44.TreeSet/TreeMap自平衡二叉树,遵循左小右大原则存放
45.遍历二叉树的时候右三种方式:
前序遍历:根左右
中序遍历:左根右
后序遍历:左右根
前中后说的是根的位置。根在前面是前序,根在中间是中序,根在后面是后序
46.TreeSet集合/TreeMap集合采用的是:中序遍历方式。Iterator迭代器采用的是中序遍历方式
47.放到TreeSet或TreeMap集合key部分的元素要做到排序,包括两种方式:
第一种:放到集合中的元素实现java.lang.Comparable接口
第二种:在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象
48.Comparable和Comparator怎么选择
当比较规则不会发生改变的时候,或者说比较规则只有一个的时候,建议实现Comparable接口。
如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议实现Comparator