1 单例集合框架图示
---->Collection接口:单例集合,用来存储一个一个的对象
>List接口:存储有序的、可重复的数据 ---->”动态“数组
>ArratList / LinkedList / Vector
>Set接口:存储无序的、不可重复的数据 ---->数学意义上的”集合“
>HashSet / LinkedHashSet / TreeSet
---->常用方法
Collection coll= new ArrayList();
//1.add(Object obj)
coll.add("AA");
coll.add(123);
coll.add("");
//2.size()
System.out.println(coll.size());
//3.addAll(Collection col);将另一个Collection实现类的元素添加进来
Collection col = new ArrayList();
col.add(0);
col.add("0");
coll.addAll(col);
System.out.println(coll.size());
//4.isEmpty();
System.out.println(coll.isEmpty());
//5.clear();清空元素
coll.clear();
System.out.println(coll.isEmpty());
//6.contains(Object obj);判断当前集合是否包含obj
//掉用的是存储对象的equals()
System.out.println(coll.contains(123));
System.out.println(coll.contains(new String("bb")));//这里判断的是内容,用的是equals()
System.out.println(coll.contains(new Person("name",18)));//这里的equals的没有重写
//7.containsAll(Collection col);
//判断形参col中的所有元素是否都在当前集合中
Collectioncol=newArrayList();
col.add(123);
System.out.println(coll.containsAll(col));
//8.remove(Objectobj)
//如果有重复的,只移除一个
//调用的也是equals
coll.remove(123);
System.out.println(coll);
//9.removeAll(Collection col);
//移除和col中一样的元素,就是做一个差集
coll.removeAll(col);
System.out.println(coll);
//10.retainAll(Collection col);
//求两个集合的交集,并返回给coll
System.out.println(coll.size());
Collectioncol=Arrays.asList(123,1245);
coll.retainAll(col);
//11.equals(Collection col);
//boolean
Collectioncoll1=newArrayList();
coll1.add("AA");
coll1.add(newString("bb"));
coll.equals(coll1);
//12.hashcode();
System.out.println(coll.hashCode());
//13.toArray();
//集合变成数组
System.out.println(coll.size());
Object[] obj=coll.toArray();
System.out.println(obj[0]);
//拓展:数组到集合::Arrays.asList(newString[]{"11","22","33"});
//14.iterator():返回Itetator接口的实例,用于遍历集合元素。
2 用Interator接口遍历Collection
//迭代器接口,用来遍历集合:提供了一种方法访问一个集合对象中各个元素,又不需要暴露该对象的内部细节
Iterator iterator = coll.iterator();
System.out.println(iterator.next());
//hasNext()
while(iterator.hasNext()){
System.out.println(iterator.next());
}
注意:每调一次,coll.iterator()方法都会生成一个新的迭代器
---->迭代器中的remove()方法:先 ierator.next(),在iterator.remove()就能删除一个元素
3 增强for循环
foreach---->for(Object obj : coll){ }
4 Collection子接口 List
---->动态数组
---->ArrayList / LinkedList / Vector三者异同
>三个类都是实现了List接口、存储的数据都是 有序的、可重复的
>不同:
>ArrayList:作为List接口的主要实现类,JDK1.2;线程不安全、执行效率高。底层使用Object[]存储。
>LinkedList:对于频繁的插入和删除操作,用这个比arrayList效率高;底层用双向链表存储。
>Vector:作为List接口的古老实现类, JDK1.0;线程安全,效率低,底层使用Object[]存储。
5 ArrayList底层源码分析(JDK7 / JDK8不一样)
*ArrayList源码分析
*1.1JDK7框架下
*ArrayListlist=newArrayList();//底层创建了一个长度10的Object[]的数组elementData
*list.add(123);//elementData[0]=newInteger(123);
*//当某次添加,导致底层elementData数组容量不够,则扩容,默认扩容为原来容量的1.5倍
*//同时需要将原有数组的数据copy到新数组中。elementData=Arrays.copyOf(elementData)
*
*结论:开发中建议使用带参的构造器
*ArrayListlist=newArrayList(initialCapacity)
*1.2JDK8框架下的变化
*ArrayListlist=newArrayList();
*//底层Object[]elementData初始化为{},并没有创建长度为10的数组
*list.add(123);
*//第一次调用add()时,底层才创建了长度为10的数组
*//后续和JDK7一样
6 LinkedList源码分析
*LinkedList源码分析
*LinkedListlist=newLinkedList();
*//内部声明了Node类型的first和last属性,默认值为null
*list.add(123);//将123封装到Node中,创建了Node对象
*
*Node定义为://可以看出LinkedList是双向的
*private static class Node<E>{
* E item;
* Node<E> next;
* Node<E> prev;
*
* Node(Node<E>prev,Eelement,Node<E>next){
* this.item=element;
* this.next=next;
* this.prev=prev;
* }
*}
7 Vector源码分析
---->源码中都是同步方法
---->通过无参构造器创建对象时,都创建了大小是10的数组,add后扩容不太一样
8 List接口的常见方法
//1.void add(intindex,Objectobj)
//index后面的往后移
list.add(1,"BB");
System.out.println(list.toString());
//2.void addAll(int index,Collectioncol);
Listlist1=Arrays.asList(1,2,3);
list.addAll(3,list1);
System.out.println(list.toString());
//3.Object get(intindex)
System.out.println(list.get(3));
//4.int indexOf(Objectobj)
//返回obj在集合中首次出现的位置
System.out.println(list.indexOf(468));
//5.int lastIndexOf(Objectobj)ni
//返回obj在集合中最后一次出现的位置
System.out.println(list.lastIndexOf(468));
//6.Object remove(intindex)
//移除指定index位置上的元素,并返回次元素
System.out.println(list.remove(4));
//7.Object set(intindex,Objectelc)
//替换指定index位置上的元素为elc
list.set(0,1234);
System.out.println(list);
//8.List subList(intfromIndex,inttoIndex):左开右闭
//返回fromIndex到toIndex位置上的子集合
9 总结常用方法
>增:add(Object obj)
>删:remove(int index) / remove(Object obj)
>改:set(int index, Object obj)
>查:get(int index)
>插:add(int index, Object obj)
>长度: size()
>遍历: Iterator / foreach
10 面试题
add(Object obj)方法没有重载方法,因此,add(2)里面2会自动装箱,而remove存在重载,则,2会倾向于直接的int index,不会自动装箱
11 set接口
---->无序的、不允许包含相同的元素
---->Set接口:存储无序的、不可重复的数据 ---->数学意义上的”集合“
>HashSet:作为Set接口的主要实现类,线程不安全,效率高,,底层其实是hashmap
>LinkedHashSet:HashSet的子类,遍历其内部数据时,可以按照添加的顺序遍历
>TreeSet:可以按照添加的对象的指定属性,进行排序
---->无序的不可重复的 理解:
>无序性:Set set = new HashSet();
>不等于随机性
>存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的Hashcode
>不可重复性:
>保证添加的元素按照equals()判断时,不能返回true,
---->Set中添加元素的过程,HashSet为例
>hashSet中既有数组,也有链表
>向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算a的哈希值,此哈希值通过某种算法得到元素a在HashSet底层数组中的存在位置,判断数组在此位置上是否有元素:
如果没有元素,添加成功---->情况1
如果有元素b(或者以链表形式存在的多个元素),则先比较元素之间的hashcode
如果hashcode不同:则a添加成功。---->情况2
如果相同,则调用a的equals()方法,
equals返回true,添加失败
equals返回false,添加成功 ---->情况3
对于情况2 和 情况3. 元素a和已经存在的元素以链表形式存在
JDK7,元素a放在数组中,指向原来的元素
JDK8,原来的元素在数组中,指向a
12 LinkedHashSet
13 TreeSet
*1.向TreeSet中添加的元素必须是同一类的
*2.两种排序方式:自然排序(实现comparable)/定制排序(实现Comparator接口)
*3.自然排序中,比较两个对象是否相等的标准是,comparable()为0,不再用equals()
*4.定制排序中,比较两个对象是否相等的标准是,compare()为0,不再用equals()
14 练习题
---->利用Set对List中的重复数值进行删除
---->p1.setName("cc")之后 p1的hash值已经变了,在进行remove操作时,用新的hash值和老的hash比较
15 Map接口
---->Map:接口,存储 键值对 key - value,类似于函数
---->HashMap:作为Map的主要实现类,线程不安全;可以存储null的key和value
---->LinkedHashMap:保证在遍历map的时候,可以按照添加时候的顺序来遍历
---->TreeMap: 保证可以按照添加的key - value对进行排序,实现排序遍历,考虑key的自然排序和定制排序
底层用的是红黑树
---->Hashtable:Map的古老实现类,线程安全;不能存储null的key和value
---->Properties:常用来处理配置文件,,key和value都是String
HashMap的底层:数组+链表(JDK7以前)
数组+链表+红黑树(JDK8以后)
面试题:
1. HashMap的底层实现原理:
2.HashMap 和Hashtable 的异同?
16 Map中key-value的理解
---->key是无序的,不能重复的 ,用set存储 |---->key所在的类需要重写equals和hashcode方法
---->value是无序的,可重复的 ,用collection存储 |---->value所在的类需要重写equals
---->一个key-value构成一个Entry对象,无序,不可重复,用set存储
17 HashMap的底层实现原理
//以下是基于JDK7
HashMap map = new HashMap();
实例化之后,底层创建了一个长度是16的一维数组:Entry[] table
map.put(key1, value1);
首先,调用key1的hashCode()方法,得到key1的hash值,此哈希值经过一定的运算,得到在Entry数组中的存放位置
如果,此位置上没有数据,则此时key1-value1添加成功 ---->情况1
如果,此位置上不为空(一个或多个数据以链表形式存在),则比较key1和其他数据的哈希值
如果,哈希值不同,则key1-value1添加成功 ---->情况2
如果,key1的哈希值,和某个已经存在的数据的key的哈希值相同,则调用key1.equals(key2)
如果,equals()返回false,则添加成功 ---->情况3
如果,equals()返回true,则用key1替换key2
说明: 对于情况2和情况3,此时,key1-value1和已经存在的数据以链表形式存在
遇到扩容的问题是,当超过临界值(且要存放的位置非空)时,扩容为原来的2倍,将原来的数据复制过来
//JDK8中的区别
1.new HashMap()的时候,底层没有创建一个长度为16的数组
2.底层的数组是Node[],而不是Entry[]
3.首次使用put()方法是,底层创建长度16的数组
4.JDK7底层的结构是:数据+链表,JDK8底层结构:数组+链表+红黑树
当数组的某一个位置上的元素以链表形式存在的个数>8,且数组长度>64时,
此时此索引位置上的数据改为红黑树存储
18 LinkedHashMap底层实现原理‘
19 Map的常用方法
总结:常用方法
>添加 Object put(Objdect key, Object value)
>产出 Object remove(Object key)
>修改 Object put(Objdect key, Object value)
>查询 Object get(Object key), 返回value
>长度,size()
>遍历 keySet() / values() / entrySet()
20 TreeMap
---->想TreeMap中添加key-value,要求key是同一类型的对象
---->按照key进行,自然排序 / 定制排序
---->comparable / comparator
21 Properties
---->常用来处理配置文件,,key和value都是String
22 Collections工具类
---->是一个操作Set List Map的工具类
---->Collectios类中提供了多个synchronizedXxx()方法,该方法可使得 指定集合包装成同步的集合,从而可以解决多线程并
发访问集合是的线程安全问题