一:Collecction接口
1.单列集合框架结构
》Collection接口:单列集合,用来存储一个一个的对象
》 List接口:存储有序的,可重复的数据---》动态数组,实现类:ArrayList,LinkedList,Vector
》Set接口,存储无序的,不可重复的数据--》高中讲的集合
实现类:Hash Set,LinkedHashSet,TreeSet
对应图示:
2.Collection常用方法:
add(Object obj),addAll(Collection coll),size(),isEmpty(),clear()
contains(Object obj),containsAll(Collection coll),remove(Object obj),removeAll(Collection coll)
retainsAll(Collection coll),retainsAll(Collection coll),equals(Collection coll),hashCOde(),toArray(),iterator()
3.Collection集合与数组之间的转换
集合---》数组:toArray()
数组---》集合 Arrays.asList(T...t)
4.使用Collection集合存储对象,要求对象所属的类满足:
向Collection接口的实现类的对象中添加数据obj时,要求obj所在的类要重写equals()
5.遍历Collection集合
1.iterator迭代器 2 foreach循环(增强for循环)
2.遍历的代码实现:
Iterator iterator = coll.iterator();
//hasNext():判断是否还有下一个元素
while(iterator.hasNext()){
//next()①指针下移,②将下移以后集合位置上的元素返回
System.out.println(iterator.next());}
3.迭代器图示:
二:List接口
1.存储的数据特点:
List 接口:存储有序,可重复的数据--》“动态数组”替换原来的数组
2:常用方法:
增:add(Object obj)
删:remove(int index), remove(Object obj)
改:set(int index,Object ele)
查:get(int index)
插:add(int index,Object ele)
长度:size()
遍历:①Iterator迭代器方式
②增强for循环
③普通的循环
3.常用实现类:
》ArrayList:作为List接口的主要实现类,线程不安全的,效率高;底层使用Object[] elementData存储
》LinkedList:对于频繁的插入,删除操作,使用此类效率比ArrayList高,底层使用双向链表存储
》vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储
4.源码分析:
ArrayList的源码分析:
1jdk7情况下:
ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组 elementData
List.add(123);//elementData[0]=new Integer(123);
...
List.add(11);//如果此次的添加导致底层elementData数组容量不够,则扩容。
默认情况下,扩容为原来的容量的1.5倍,同时需要将原来的数组中的数据复制到新数组中
结论:建议开发中使用带参的构造器:ArrayList list= new ArrayList(int capacity)
2jdk8中的ArrayList的变化:
ArrayList list = new ArrayList();//底层 Object[] elementData初始化为{},并没有创建长度为10的数组
List.add(123);//第一次调用add()时,底层才创建了长度10的数组,并将数据添加到elementData[0]
后续的添加和扩容操作与jdk7无异
3 小结:jdk7中ArrayList的对象的创建类似于单列的饿汉模式,而jkd8中的ArrayList对象创建类似于单列的懒汉式,延迟数组的创建,节省内存
三:Set接口
1.存储的数据特点:
无序的,不可重复的数据
具体的以HashSet为例说明:
》无序性:不等于随机性。存储的数据在底层数组中并非按照数组的索引顺序添加,而且根据数据的哈希值决定的
》不可重复性:保证添加的元素按照equals()判断不能返回true,即相同的元素只能添加一个
2.元素的添加过程:(以HashSet为例)
我们在向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值
,此哈希值接着通过某种计算方法计算出在HashSet底层数组中存放位置(即为:索引位置,判断数组此位置上是否已经有元素:
如果此时位置上没有其他元素,则元素a添加成功---》情况1
如果此位置上有其他元素b(或以链表形式存在的多个元素,则比较元素a与元素b的hash值:
如果hash值不同,则元素a添加成功----》情况2
如果hash值相同,进而调用元素a所在类的equals()方法:
equals()返回true,元素a添加失败
equals()返回false,元素a添加成功----》情况3
对于添加成功的情况2和情况3而言:元素a与已经存在的指定索引位置上的数据以链表的方式存储。
jdk7:元素a放在数组中,指向原来的元素
jdk8:原来的元素在数组中,指向元素a
总结:七上八下
HashSet底层:数组+链表的结构
3.常用方法:
Set接口中没有额外定义新的方法,使用的都是Collection中声明的方法
4.常用实现类
》HashSet:作为Set 接口的主要实现类;线程不安全的可以存储null值
》LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历,对于频繁的遍历操作,LinkedhashSet效率高于HashSet
》TreeSet:可以按照添加对象的指定属性,进行排序
5.存储对象所在类的要求:
HashSet/LinkedHashSet:
要求:向Set(主要指:HashSet,LinkedHashSet)中添加数据,其所在的类一定要重写
HashCode()和equals
要求:重写的hashcode()和equals()尽可能保持一致性:相同的对象必须有相同的散列码
重写两个方法的小技巧:对象中用作equals()方法比较的Filed,都应该用来计算hashcode值
TreeSet:
1.自然排序中,比较两个对象是否相同的标准为:compareTo() 返回0,不在是equals()
2.在定制排序中,比较两个对象是否相同的标准为:compare() 返回0,不在是equals()
6.TreeSet的使用:
1.使用说明:
》向TreeSet添加数据,必须是相同类的对象
》两种排序方式:自然排序实现Compareable接口和定制Comparator
四:Map接口
1.常用实现类结构
--Map:双列数据,存储key-value对的数据 ------ 类似高中的函数:y=f(x)
》HashMap:作为Map的主要实现类,线程不安全的,效率高;存储null的key和value
--LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历
原因:在原来的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素
对于频繁的遍历操作,此类执行效率高于HashMap
》TreeMap: 保证添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序底层使用红黑树
》Hashtable:作为古老的实现类;线程安全的,效率低,不能存储null的key和value
---Properties:常用来处置配置文件。key和vaule都是String类型
HashMap的底层:数组+链接(jdk7及以前)
数组+链表+红黑树(jdk8)
2.存储结构的理解:
》Map中的key:无序的,不可重复的,使用Set存储所有的Key--key所在的类要重写equals()和hashcode()以hashMap为例
》Map中的value:无序的,可重复的,使用Collection存储所有的value---》value所在的类要重写equals()
》Map中的entry:无序的,不可重复的,使用Set存储所有的entry
3.常用方法:
*添加: put(Object key,Object value)
*删除:remove(Object key)
*修改: put(Object key,Object value)
*查询:get(Object key)
*长度:size()
*遍历:KeySet()/values()/entrySet()
4.内存结构:
4.1 HashMap 在jdk7中实现原理:
HashMap map =new HashMap()
* 在实例化后,底层创建了长度时16的一维数组Entry[]table
map.put(key1,value1):
*首先,调用key1所在类的hashcod()计算key1哈希值,此哈希值经过某种算法计算后
得到在Entry数组中的存放位置
* 如果此位置上的数据为空,此时的key1-value1 添加成功----情况1
* 如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在))
比较key1和已经存在的一个或多个数据的哈希值:
*如果key1的哈希值与已经存在的哈希值都不相同,此时的key1-value1 添加成功---情况2
*如果key1的哈希值与已经存在的某一个数据(key2-value2)的哈希值相同,继续比较调用 key2所在类的equals(Key2)方法:
如果equals()返回false:此时的key1-value1 添加成功----情况3
如果equals()返回true:使用value1替换value2
补充:关于情况2和情况3:此时 key1-value1和原来的数据以链表的方式存储
在不断的添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时。扩容的默认方式:扩容为原来容量的2倍,并将原来的数据复制过来
4.2 HashMap 在jdk8中相较于jdk7 底层实现不同:
1.new HashMap():底层没有创建一个长度为16的数组
2.jdk8 底层的数组时Node[] ,而非Entry[]
3.首次调用put()方法时,底层创建一个长度为16的数组
4.jdk7 底层结构只要 数组+链表,jdk8中底层结构:数组+链表+红黑树
*当数组的某一个索引位置上的元素以链接形式存在的数据个数>8,且当数组长度>64,
此时的索引位置上的所有数据改为使用红黑树存储。
4.3:TreeMap的使用
*向TreeMap中添加key-value,要求key必须由同一个类创建的对象
*因为要按照key进行排序:自然排序,定制排序
4.4 使用Properties 读取配置文件:
public static void main(String[] args) { Properties pro = new Properties(); FileInputStream fileinput=null; try { fileinput =new FileInputStream("jdbc.properties"); pro.load(fileinput); String name = pro.getProperty("name"); String password =pro.getProperty("password"); System.out.println(name); System.out.println(password); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { fileinput.close(); } catch (IOException e) { e.printStackTrace(); } }
五:Collections工具类:
1.作用:
操作Collection和Map工具类
2.常用方法:
*reverse(List):反转List中元素的顺序
*shuffle(List): 对List 集合随机排序
*sort(List):根据元素的自然顺序对指定List 集合元素升序排序
*sort(List,Compartor)::根据指定的Comparator产生的顺序对List 集合元素升序排序
*int frequency(Collection Object):返回指定集合中指定元素的出现次数
*voidcopy(List dest,List src):将src的中的内容复制到dest中
* boolean replaceAll(List list,Object oleVal,Object newVal):使用新值替换list 对象所有的旧值
3.面试题:Collection 和Collections区别
Collection:集合接口
Collections 操作Collection 和Map接口的工具类