-
集合概述
a) 对多个数据进行存储,简称java容器
b) 动态地把多个对象的引用放入容器中
c) 与数组对比
i. 数组初始化后,长度确定。
ii. 数组需要定义数组类型,定义后是确定的 -
Java集合两种体系
-
Collection
a) 单列数据,定义了存取一组对象的方法的集合
i. List:元素有序,可重复集合
ii. Set:元素无序,不可重复集合 -
Map
a) 双列数据,具有映射关系“key—value对”的集合 -
Collection API
a) Add(Object e): 将元素e添加到集合当中
b) addAll(Collection coll):将集合coll中的元素添加到当前的集合中
c) Size(): 添加的元素的个数
d) Clear(): 清空集合元素
e) isEmpty(): 判断当前集合是否为空 -
Collection.List
a) ArrayList:Collection coll = new ArrayList();
i. Coll.contains(Object obj);判断集合中是否包含object 默认调用equals()!!注意调用的object是否重写了equals方法—>自定义类需要重写equals()方法
ii. Coll.containAll(Collection coll1):判断是否包含所有coll1的数据
iii. Coll.remove(Object obj): 移除obj数据,调用equals()方法
iv. Coll.removeAll(Object obj):
v. Coll.retainAll(Object obj): 求两个集合的交集
vi. Object[] arr = Coll.toArray(); 集合转化为数组
vii. List list = Arrays.asList(new String(){“aa”}); 数组转化为集合 返回list(list想当动态数组,元素有序可重复集合)
viii. Iterator:返回iterator接口的实例,用于遍历元素 -
Iterator
a) 其对象称为迭代器,是一种设计模式,用于遍历Collection集合中的元素
b) Iterator iterator = coll.iterator();
c) Iterator.next(); 返回下一个元素 –>异常:noSuchElementException
d) Iterator.hasNext(); 是否有下一个元素
e) Iterator.remove; 可以删除集合的元素,使用的是迭代器对象的remove方法 -
Foreach循环遍历—增强for循环
a) 可以遍历集合Collection和数组
b) 底层调用的是Iterator来完成操作
c) 遍历操作不需要Collection和数组的长度,无需使用索引访问元素。
d) For(Object obj : coll){} // for (集合元素的类型 局部变量 : 集合对象) 代码块中修改obj 不会改变原集合coll的元素 -
List接口:存储有序 可重复的数据
a) ArrayList:List接口的主要实现类,线程不安全,效率高,底层使用Object[]数组
b) LinkedList:对于频繁的插入和删除操作,其效率更高,底层使用双向链表存储
c) Vector:古老实现类,线程安全,效率低,底层使用Object[]数组
d) 三个的异同
i. 同:都是实现了List的接口,存储数据特点相同
ii. 不同:同上 -
ArrayList源码
a) ArrayList list = new Arraylist(); 创建了长度为10的Object[]数组elementData
b) 添加到第11次,底层数组容量不够,则默认扩容为原来的1.5倍,length = old + (old>>1) 右移一位除于2,将原有的数组复制到新的数组
c) ArrayList list = new ArrayList(int initialCapacity):初始化数组大小
d) JDK8 时,创建对象时底层elementData初始化为{},在调用add方法才创建数组长度,节约资源。JDK7 时,对象创建立即创建长度为10的数组 -
LinkedList源码
a) 是一个双向链表
b) LinkedList LL = new LinkedList(); 内部声明了Node类型的first、last属性,默认为null
c) List.add(123); //将123封装到node中 -
Vector源码 不怎么用
a) 默认扩容为原来的2倍,线程安全的。
b) 创建对象是底层都创建了长度为10的Object[]数组 -
ArrayList方法
a) 是collection的子接口,Collection 中的方法都可以用
b) Void add(int index, Object ele); 在index位置插入ele元素
c) addAll(index index, Collections coll); 将集合coll中的所有元素加入
d) Object get(int index): 获取指定index位置的元素
e) Int indexOf(Object obj): 返回首次出现的元素的索引,找不到返回-1
f) Object remove(int index):移除指定位置的元素,并返回该元素(和Collections对比是方法的重载,不同的参数列表)
g) Object set(index, obj);
h) List subList(int fromIndex, int toIndex): 返回子集合 左闭右开 -
Set接口
a) Set:元素无序,不可重复集合
b) 接口没有提供额外的方法
c) 根据equals()判断两个对象是否相同
d) HashSet:set接口的主要实现类;线程不安全;可以存储null值 底层:数组加链表结构
i. LinkedHashSet:作为HashSet子类,遍历内部数据可以按照添加的顺序遍历
e) TreeSet:放入的数据是同一个类,按照添加的对象的指定属性进行排序(comparable) -
存储无序性和不可重复性
a) 无序性:存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定。不等于随机性
b) 不可重复性:保证添加的数据(利用到哈希值)按照equals()方法判断时,不能返回true
c) 添加元素过程,HashSet为例:
i. 添加元素a,调用a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为索引位置)
ii. 判断存放位置上是否有元素,若无元素,a直接添加
iii. 若存在其他元素b(或以链表形式存在的多个元素),则比较元素a和元素b的hash值,若不相同,则a添加(七上八下) -
若hash值相同,则调用元素a所在类的equals()方法
a) 返回true,元素已经存在,添加不成功
b) 返回false,添加成功
iv. Jdk7:元素a放到数组中,指向原来的元素
v. Jdk8:原来数组中的元素,指向元素a
d) 扩容:若使用率超过75%,则扩大为原来的两倍(初始16,扩容为32) -
HashCode()重写方法
a) 向set中添加数据,一定重写equals和hashCode方法!!
b) 重写的hashCode和equal方法尽可能保持一致性—相同的对象有相同的散列码(hashcode)
c) 使用31乘
i. 可以减少哈希码相同的冲突,增加了查找的概率
ii. 31只占用5bits,数据溢出概率小
iii. 算法效率高,相当于i*31 == i<<5-1
iv. 31是一个素数 -
LinkedHashSet
a) 作为hashSet的子类,在添加数据的同时维护了一对双向链表,记录前一个数据和后一个数据
b) 优点:对于频繁的遍历操作,效率高。 -
TreeSet—底层采用红黑树,是一种二叉树
a) 添加的对象,必须是同一个类的对象,使得可以从小到大排序
b)
c) 自然排序(实现comparable接口)和定制排序(实现comparator)
i. 自然排序 -
比较对象使用compareTo(),而不是equals。对类实现comparable接口
ii. 定制排序 -
Comparator com = new comparator(@override…) ; TreeSet ts = new TreeSet(com);
-
比较对象使用compare()方法,不再是equals
-
HashSet底层实现原理
a) 新建一个HashMap的对象
b) 将数据存放在HashMap的key值中,value值为static final Object Present = new Object, 使得所有的value都为同一个静态Object 对象PRESENT -
Map --接口
a) 双列数据
b) HashMap—Map的主要实现类;线程不安全,效率高;可以存储null的key、value
i. LinkedHashMap—在遍历map元素是,保证添加的顺序进行遍历 -
原因:在原有的HashMap基础上,添加了一对指针,指向前一个和后一个元素
-
频繁的遍历操作,效率更高
-
底层使用数组+链表+红黑树(jdk8)
c) TreeMap—根据添加的key、value对进行排序,实现排序遍历
i. 考虑key的自然排序和定制排序
ii. 底层使用红黑树
d) Hashtable—古老的实现类;线程安全;效率低;不可存储null
i. Properties–常用来处理配置文件,key和value都是String类型 -
Map结构
a) Map中的key:无序的、不可重复的,使用set存储所有的key。HashMap重写HashCode和equals。
b) Map中的value:无序的,可重复的,使用collection去存储。Value所在类重写equals
c) 一个键值对:构成Entry对象
i. 无序的,不可重复的,利用set存储所有entry -
HashMap 在jdk7的底层原理
a) HashMap map = new HashMap();
i. 实例化后,创建长度为16的一维数组Entry[] table。
b) Map.put(key1, value1):
i. 首先,调用key1所在类的hashCode()计算哈希值,得到存放位置
ii. 数据为空,添加成功
iii. 不为空,比较key1和已经存在的数据的哈希值,若都不相同,添加成功
iv. 不为空,比较key1和已经存在的数据的哈希值,存在相同,调用key1的equals(key2)方法,比较的是key,若不相同,添加。
v. 若调用equals方法返回true:使用value1替换原value,相当于修改操作
c) 添加过程的扩容问题,扩容为原来的二倍,将原来的数据复制过来 -
HashMap 在jdk8的底层原理
a) New HashMap—底层没有创建数组
b) 首次调用put(), 底层创建长度为16的数组
c) 底层的数组是Node[],而非Entry[]
d) 底层结构式数组+链表+红黑树
e) 当数组的某一个索引位置上的元素以链表形式存在的数据个数>8 且数组长度大于64,则索引上的所有数据改为红黑树存储。 -
HashMapJDK7源码
a) 不管初始化的大小是什么,初数长度一定是2的几次幂。
b) LoadFactor—加载因子0.75,用于计算临界值。提前扩容的原因用于减少链表的产生,而且数组不一定全部放满,都生成了链表了。
c) Threshold—临界值,超过临界值开始扩容,为LoadFactorcapacity,第一次为0.7516 = 12;
d) 根据key存放到特定index中:使用&与的位运算符
i. Return h&(length-1);相对于取余数%效率高,保证位于数组中
e) 在不断添加的过程中,当超出临界值且要存放的位置非空(形成链表),则扩容到原来的二倍。数组复制到扩容后的数组,被重新放各个数据。
f) CreatyEntry操作—table[bucketIndex] = new Entry<>(hash, key, value, e);
i. 其中 hash,key,value为新加入的键值对
ii. e为原来的bucketIndex位置的键值对,构造器用next描述,表示新的键值对指向原来的键值对,形成链表 -
HashMapJDK8源码
a) 对象创建时,只赋值了加载因子,没有创建底层长度16数组
b) 不再是Entry 而是Node<K,V>[] table;
c) 当一条链上的数据超过8(treeify_THRESHOLD)时,且当前数组的长度大于64时,将链上的数据转为树结构
d) -
LinkedHashMap底层原理
a) 重写了父类的newNode方法
b) 内部类Entry继承了父类HashMap的内部类Node
i. 增加了before和after属性,用于记录添加元素的先后顺序 -
Map中常用的方法
a) Map map = new HashMap();
b) 添加
i. Map.put(Object key, Object Value);
ii. Map.putAll(Map m): m中的所以键值对放到map中
c) 修改
i. Map.put(Object key, Object Value); 将原来key上的值改为Value的值
d) 删除
i. removeValue = Map.remove(Object key): 根据key值移除键值对,返回移除的value。不存在返回null
e) 清空
i. map.clear(): 不是将直接map = null(相当于map.size()会有空指针异常),只是清空里面的数据
f) 元素查询
i. Map.get(Object key):返回value 没有返回null
ii. Map.containKey(Obj key); Map.containValue(Obj value); 是否包含指定的key或者value
iii. Int size(); 返回多少对键值对
iv. Equals(Obj obj): 判断当前map和参数对象obj是否相等
g) 元试图操作方法—不用迭代器遍历(用于collection方法)
i. 所有key构成set,value构成collection,键值对构成Entry对象,也是set
ii. 将上面的调用迭代器iterator即可遍历
iii. 遍历key -
Set set = map.keySet(); ->Iterator it = ser.Iterator();
iv. 遍历value -
Collection values = map.values();
v. 遍历key—value -
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
a) Entry是map中的内部接口 -
Iterator<Map.Entry<String,Integer>> it = entry.Iterator();
-
Object obj = it.nextValue();
-
得到的是entry对象,进行强转
-
Map.Entry entry = (Map.Entry)obj;
-
或者直接Map.Entry<String, Integer> entry = it.next();
-
调用Entry类的getKey和getValue方法
-
TreeMap方法
a) 向treeMap中添加keyValue,key必须为同一对象,用于排序
b) 自然排序:类中实现的comparable和定制排序构造器重写comparator -
Properties
a) 用于配置文件,key和value都是String类型 -
Collections工具类
a) 操作Set,list,Map等集合的工具类
b) 多为静态方法
c) Collection是集合接口,Collections是工具类
d) Reverse(list), sort(list), shuffle(list): 对list进行处理,反转,排序(自然排序or定制排序),随机排序
e) Object max(Collection, comparator): 获取collection中最大值
f) Int frequency(Collection, Object): Object出现了几次
g) List dest = Arrays.asList(new Object[list.size()]);
i. 先将两个数组的size设成相同
ii. Collections.copy(dest, list)复制操作
h) 线程安全方法ArrayList和HashMap都不安全
i) Collections.synChronizedXxxx() 方法
j) List list1 = Collections.synchronizedList(list);
Java基础点:集合
最新推荐文章于 2024-10-16 10:13:45 发布