已经参加工作,利用工作之余的时间,巩固一下基础内容。
java是面向对象语言,对事物的体现一般都是以对象的形式。为了方便对多个对象的操作,就需要对对象的存储。
集合相当于一种容器,动态的把对象的引用放入容器中。
集合和数组都是对多个数据进行存储操作的结构,简称java容器。
数组在存储数据的缺陷:
1、数组一旦初始化,长度不可变
2、数组中提供的功能非常有限,对于增删改不便操作,非常容易出现空指针。
3、数组存储数据数据都是有序的可重复的,对于要求不可以重复的数据数组做不到。
java集合分为collection和map俩个体系
collection接口:单列数据,用来存储一个一个的对象
---------list接口:有序的可重复的集合 _动态数组
Arraylist、LingkedList、Vector
---------set接口:无序的不可重复的集合
HashSet、LingkedHashSet、TreeSet
Map接口:双列数据,一对一对的数据,key-value
HashMap、LingkedHashMap、TreeMap、HashTable、Properties
collection接口
add(Object e ):将元素e添加到集合中,填写自定义类需要重写equals()
addAll(Collection c):将c 集合中添加到当前的集合中
size( ):获取所添加元素的个数
isEmpty( ):判断当前集合是否为空(是否有元素) 是-返回true、否则返回false;
clear():清空集合中的元素
contains(Object obj):判断当前集合中是否包含obj这个元素。
在判断时会调用obj对象所在的类的equals(),一般自定义的类需要重写equals方法。
containsAll(collection c): 判断c集合中的元素是否都在调用本次方法的集合的集合中。
remove(Object obj):从当前集合中移除obj 元素,成功返回true;
removeAll(collection c):从当前集合中移除c集合中的所有元素(两个集合共有的元素)
retainAll(collection c):获取当前集合和c 集合的交集,保留两个集合共有的部分,删除不一样的。
equals(Object obj):判断当前集合和形参集合是否相同。
hashcode():判断当前元素的哈希值
iterator():返回Iterator接口的实例,用于遍历集合元素,
集合转变为数组
toArray();
数组变为集合
List list = Arrays.asList(new String[]{“123”,“456”,“789”});
迭代器
iterator.hashnext():指针,在第一个元素之前
iterator.next():指针下移,将下移以后位置上的集合返回
iterator.remove():可以在遍历的时候删除元素,不同于集合调用的remove()
增强for
底层还是迭代器
collection coll = new ArrayList();
for (Object obj : coll){
//集合中元素类型 局部变量 : 集合对象
}
ArrayList \LinkedList\Vector 异同:
相同点:都是属于List接口下的,有序的可重复的。
ArrayList:动态数组,线程不安全效率高。是List接口的主实现类,底层使用的Object [] elementData
LinkedList:底层使用的双向链表存储 插入和删除 使用此类效率高
Vector:线程安全效率低,底层使用的Object [ ] elementData
ArrayList源码分析
jdk1.7----
ArrayList list = new ArrayList();//底层创建了一个长度为10的Object [ ] elementData;
list add(11):此次添加导致底层Object [ ] 数组不够用,扩容。默认1.5倍,同时将原数组中的数据复制到新数组中。
建议使用有参构造。
ArrayList list = new ArrayList( int capacity);创建指定大小的集合。
jdk1.8----
ArrayList list = new ArrayList();//底层创建了一个Object [ ] elementData 初始化为空的数组,在首次使用add()时底层才会创建长度为10的数组;
list add(11):此次添加导致底层Object [ ] 数组不够用,扩容。默认1.5倍,同时将原数组中的数据复制到新数组中。
LinkedList源码分析
LinkedList list = new LinkedList( );内部申明了一个Node类型的first和last属性,默认值
null。当list.add(123);将123封装到Node ,创建了Node对象。体现了链表的双向性。
List接口的常用方法
add(int index , Object obj );在index位置插入obj元素,后边元素往后移
addAll(int index , collection c ): 在index指定位置加入c集合中的所有元素
get(int index ):获取指定位置的元素
int indexOf(Object obj):这个obj元素在集合中首次出现的位置。没有返回-1
int LastIndexOf(Object obj ):这个元素obj最后一次出现的位置。没有返回-1
remove(int index)移除指定位置的元素,并且返回这个元素。
Object set(int index , Object obj):设置index位置的元素为obj
List suList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集和(包头不包尾)
set接口
————set 无序的、不可重复的
——————HashSet:set接口的主要实现类,线程不安全,可以存储null
————————LinkedHashSet:作为Hashset的子类,遍历其内部数据时,可以按照添加的顺序来遍历。
——————TreeSet:可以按照添加的对象指定属性进行排序。
set接口:无序的不可重复的。————>无序性:不等于随机性,以HashSet为例,存储的数据在底层数组中并非按照索引的顺序来存储的, 根据所存数据的哈希值来确定在数组中的位置。
----------->不可重复性:保证添加的元素使用equals()不能返回true,即相同的元素智能存一个。
添加元素的过程,以HashSet()为例:
向hashset中添加元素A 首先调用元素A所在类的hashcode()来计算哈希值,此哈希值通过某种算法计算出在hashset底层数组中的存放位置, 判断数组此位置上是否已经有元素如果此位置没有元素,则A直接添加成功,如果此位置上有其他元素B,或者已经有以链表形式存在的多个元素,首先比较元素A和元素B的哈希值,如果哈希值不相同则元素A添加成功,如果哈希值相同,进而需要调用元素A 的equals(),方法返回true表示元素A 添加失败,返回falsa ,元素A 添加成功。 对于后两种添加成功,元素A 与已经在指定位置的数据以链表的形式储存下来。
jdk7:元素A放在数组中,指向原来的元素
jdk8:原来的元素还在数组中,元素A指向数组中原来的元素。
LinkedHashSet()
作为Hashset的子类,在添加元素的同时,每个数据还维护了俩个变量,记录此数据的前一个元素和后一个元素的位置。
TreeSet( )
1.添加的数据要求是相同类的对象,可以按照属性排序
2.两种排序方式:自然排序(compareTo接口)和定制排序(comparator)
自然排序中比较两个对象是否相同的标准时:compareTo( )返回值为 0 , 不再是equals()
定制排序中比较两个对象相同的方法标准为 compare( )返回值为0 ,不再是equals()。
Map接口
|-----Map:双列数据 key-value 类型。
|------------HashMap : 作为Map的主实现类,线程不安全,对应的效率高。可以存储null 的key和value
|-------------------LinkedHashMap:保证遍历Map的元素时可以按照添加的顺序实现遍历,原因是 :在原有的HashMap底层结构基础上,加了一对引用(指针),指向前一个和后一个元素,对于频繁的遍历操作,执行效率高于HashMap.
|------------TreeMap:可以按照添加的key -value进行排序,实现排序遍历。按照key来排序。自然排序和定制排序。底层是红黑树。
|------------Hashtable:作为Map的古老实现类,线程安全效率低。不可以存储null 的key和value
|-------------------Properties:常用来处理配置文件,作为Hashtable的子类,key–value 都是String类型。
HashMap底层: 数组+链表(jdk7以前)|
————————数组+链表+红黑树(jdk8)
Map结构的理解:
Map中的key:无序的、不可重复的,相当于使用set存储。要求key所在的类重写equals和hashcode。(以hashmap为例)
Map中的value:无序的、可重复的。要求value所在的类重写equals()
一对key-value 构成了一个Entry对象,使用set存储。
Map中的Entry对象:无序的、不可重复的。使用set存储。
HashMap底层实现原理:(jdk7)默认扩容为原来的两倍,并将原有数据复制过来。
HashMap map = new HashMap( );//在实例化之后,底层会创建一个长度为16的一维数组,Entry[ ] table.
-------map.put(key2,value1):
1、首先调用key2所在的类的hashcode(),取得哈希值,然后这个哈希值经过一定的算法处理,确定在Entry [ ] 中的索引位置。
2、如果这个索引位置上没有数据(为空),此时key2- value2添加成功。
3、如果这个索引位置上有值(说明此位置存在着一个数据或者(以链表的形式存在)多个数据) ,(利用哈希值计算出来的索引相同,并不代表俩个数据key的哈希值相同)比较key2和已存在数据key1的哈希值:
(1)key2的哈希值和已经存在数据的哈希值都不相同,此时key2 - value2添加成功。(链表形式)
(2)key2的哈希值和已经存在数据(key1–value1)的哈希值相同,继续比较,利用key2所在类的equals(key1)
如果返回true,使用value2替换已存在的value1
如果返回false,此时key2- value2 添加成功。(链表形式)
添加的过程中会涉及扩容的问题,临界值>12且其要存放的位置是一个非空状态,扩容为原来的2倍,并将原有的数据复制过来。
jdk8之后相较于jdk7底层有点不同。
(1)Entry[ ]变为Node[ ]
(2)HashMap map = new HashMap( );//在实例化之后,底层不会创建数组。
(3)首次map.put()底层才会创建一个长度为16的一维数组,Node[ ] table.
(4)jdk7底层数据结构——数组+链表
--------jdk8底层数据结构——数组+链表+红黑树。
当数组的某一个索引位置上的元素以链表的形式存在的个数>8并且数组的长度>64,此时索引位置上的所有数据改用红黑树存储。
HashMap和Hashtable的异同:
答案在上边
CurrentHashMap 和Hashtable 异同:
过几天结合线程讲解。