目录
集合框架的概述
集合,数组都是对多个数据进行存储的结构,简称Java容器。
说明:此时的内存,主要是内存层面的存储,不涉及到持久化的储存(.txt,jpg,avi等等)
集合与数组
数组在储存多个数据方面的特点
1.一旦初始化以后,其长度就确定了。
2.数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定的数据了。
比如:Stirng【】arr ;int【】arr1 ;Object【】 arr2;
数组在存储多个数据方面的缺点
1.一旦初始化以后,其长度就不可修改。
2.数组中提供的方法非常有限,对于添加,删除,插入数据等操作,非常不便
同时效率不高。
3.获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
4.数组存储数据的特点:有序,可重复,对于无序不可重复的需求,不能满足。
集合和数组的区别
Java体系分类
集合的框架
Collection接口:单列集合,用来存储一个一个的对象。
List接口:存储有序,可重复的数据。—> (“动态”数组)
Set接口:存储无序的,不可重复的数据。—>(类似高中讲的“集合”)
Map接口:双列集合,用来存储一对(key – value)一对
数据。 —>(类似高中的函数y = f(x) )
集合实例化:
Collection col = new ArrayList();
col.add(123); //自动装箱
col.add(new Date());
col.add("abc");
...
Collection常用方法
常用集合的分类
List接口实现类的对比
(1)ArrayList:底层数据结构是数组,查询块,增删慢,线程不安全,效率高。
(2)LinkedList:底层数据结构是链表,查询慢,增删快,线程不安全,效率高。
(3)Vector:底层数据结构是数组,查询快,增删慢,线程安全,效率低。
Iterator迭代器-遍历集合元素
集合元素的遍历操作,使用迭代器Iterator接口
- 内部的方法:hasNext()和next()
- 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素。
Collection collection = new ArrayList();
collection.add(123);
collection.add("aa");
collection.add(new String("bb"));
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
输出结果:
Iterator迭代器原理
foreach循环遍历集合 (增强for循环)
增强for循环的方式遍历集合
//格式:集合元素类型 局部变量 :集合对象
for(Object obj :collection){
system.out.print(obj);
}
增强for循环的方式遍历数组
//格式:数组元素类型 局部变量 :数组对象
int arri = new int[]{1,2,3};
for(int num :arri){
system.out.print(num);
}
//foreach原理:foreach在运行时调用了迭代器(Iterator)
//迭代器调用hasNext,取出值“复制”给局部变量。
List接口
List实现类
ArrayList:作为List接口的是实现类,线程不安全,效率高,底层使用object[]。
Vector:作为List接口的古老实现,线程安全,效率低,底层使用object[]。
LinkedList:双向链表,对于频繁插入,删除操作,使用此类效率比ArrayList高。
ArrayList的源码分析
jdk7的情况下
1.ArrayList list = new ArrayList(); //底层创建了长度是10的Object[]数组elementData
list.add(123);//相当于elementData[0] = new Integer(123);
2.若向数组内增加元素到达10以后,在添加,导致容量不足,则需要扩容。
3.默认情况下,扩容为原来容量的1.5倍,同时需要将原有的数组中的数据复制到新数组中。
结论:在使用时可以使用带参的构造器 —>new ArrayList( int capacity) 指定长度。
jdk8中ArrayList的变化
1.ArrayList list = new ArrayList(); //底层Object[ ] element初始化为{ }。
并没有创建数组。
2.list.add(123); //第一次调用add( )时,底层才创建了长度10的数组,并
将数据123添加到数组element中,扩容和jdk7无异。
List中常用方法
void add(int index, E element)
在指定位置插入元素,后面的元素都往后移一个元素。
boolean addAll(int index, Collection extends E> c)
在指定的位置中插入c集合全部的元素,如果集合发生改变,则返回true,否则返回false。
意思就是当插入的集合c没有元素,那么就返回false,如果集合c有元素,插入成功,那么就返回true。
E get(int index)
返回list集合中指定索引位置的元素
int indexOf(Object o)
返回list集合中第一次出现o对象的索引位置,如果list集合中没有o对象,那么就返回-1
E remove(int index)
删除指定索引的对象
E set(int index, E element)
在索引为index位置的元素更改为element元素
ListsubList(int fromIndex, int toIndex)
返回从索引fromIndex到toIndex的元素集合,包左不包右
长度:size()
一道关于List-remove操作的面试题
说明:
List中重载了collection的remove方法,
List中的remove方法是删除指定索引位置的元素
collecation是删除相同的指定元素。
在形参列表中直接输入数字,会被解释器当成索引,若想使输入的数字当成指定元素,则需要使用匿名包装类的方式:
new Integer(number)
集合–Set接口
框架
|—-Collection接口:单列集合,用存储一个一个的对象
|—-Set接口:存储无序的,不可重复的数据 —>高中讲的”集合“
|—-HashSet:作为Set接口的主要实现类,线程不安全,可以存储null知
|—-LinkedHashSet:作为HashSet的子类,遍历时可以按照添加时输出
|—-TreeSet:可以按照添加对象的质地的指定属性,进行排序。
Set的三个实现类
HashSet
LinkedHashSet
TreeSet
Set无序性和不可重复性说明:
无序性:不等于随机性,存储的数据结构在底层数组中并非按照数组索引的顺序增加,而是按照数据的哈希值经过某种算法计算出存储的位置。
不可重复性:保证增加的元素按照equls()判断时,不能返回true,既:相同的元素只能添加一个。
Set增加元素的过程(已HashSet为例)
我们向HashSet中添加元素a,首先调用元素a所在类的hashcode()方法,计算元素a的哈希值,此哈希值通过某种算法计算出在HashSet底层数组的存放位置(既为“索引位置“)判断数组此位置上是否有元素:
|—如果此位置没有元素,则a增加成功
|—如果此位置上存在元素b(或存在“链表“),则比较元素a和 元素b的hash值
|——–|-如果哈希值不相同,则元素增加成功
|——–|-如果哈希值相同,进而调用元素a所在类中的equlas()方法
|————|-equlas()返回true:元素增加失败
|————|–equlas()返回false:元素增加成功
在增加成功的情况下:jdk7和jdk8链表存放方式有区别:
jdk7:新增元素放到数组中,指向原来的元素
jdk8:原来的元素放到数组中,指向新增元素
LinedHashSet的使用
LinedHashSet作为HashSet的子类,在添加数据的同时,还维护了两个引用,记录此数据的前一个数据和后一个数据。
优点:
对于频繁的遍历操作,LinedHashSet效率更高一些
TreeSet(二叉树式的存储方式)—-底层为红黑树
1.向TreeSet中增加的数据,要求是相同类型的对象
2.TreeSet底层存储元素的两种排序方式:自然排序(实现Comparable接口并实现其中的compareto()方法)和定制排序(在创建TreeSet时创建Comparator对象,并实现compare方法)。
HashSet的具体使用—删除集合中重复项
(利用Set的不可重复性)
Set内部存储理解
(Person类中有get(),set(),equals(),hashCode()等 方法)
集合—Map接口
Map接口框架
Map结构简单介绍
|—Map:双列数据,存储key-value对的数据—类似于高中函数 y = f(x)
|—HashMap:作为Map的主要实现类,线程不安全,效率高
|—LinkedHashMap:保证在遍历map元素时,可以按照添加顺序遍历
|—TreeMap:保证按照添加的key-value对进行排序,底层使用红黑树
|—Hashtable:作为古老的实现类,线程安全,效率低,不能存储null的值
|—Properties:常用来处理配置文件,key-value都是String类型
HashMap的底层
数组HashMap的底层:
数组+链表 (jdk7及以前)
数组+链表+红黑树 (jdk8)
Map结构的理解
1.Map中的key:无序的,不可重复的,使用Set存储所有的key—>key所在的类要重写equals()和hashCode() 。
2.Map中的value:无序的,可重复的,使用Collection存储所有的value—>value所在的类要重写equals()
3.Map中的entry:无需的,不可重复的,使用Set存储所有的entry
HashMap底层原理实现—jdk7
1.HashMap map = new HashMap();
2.在实例化以后,底层创建了长度时16的一维数组Entry【】table。
…可能已经执行多次put()…
3.map.put(key1,value1):
4.首先,调用key1所在类的hashCode()计算key1的哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。
5.如果此时位置上的数据为空,此时的key1-value1添加成功—情况一
6.如果此位置上数据不为空(意味着此位置上存在一个或多个数据(链表形式存在)),比较key1和已经存在的数据的哈希值:
7.如果key1的哈希值与已经存在数据的哈希值都不相同,此时的key1-value1添加成功—情况二
8.如果key1的哈希值和已经存在数据的哈希值相同,继续比较,调用key1所在类的equals(),如果返回false;此时的key1-value1添加成功—情况三 ,如果返回true,使用value1替换掉已经存在数据的value值。
补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。
在增加的过程中,会涉及到扩容问题,默认的扩容方式是:
扩容为原来的2倍,并将原来的数组复制过来。
HashMap底层原理实现—jdk8
(区别于jdk7)
1.new HashMap( ) :底层没有创建一个长度为16的数组。
2.jdk8底层的数组是:Node【】,而非Entry【】。
3.首次调用put()方法时,底层创建长度为16的数组。
4.jdk7底层结构只有:数组+链表。jdk8中底层结构:数组+链表+红黑树
当数组的某一个索引位置上的元素与链表形式存在的数据个数>8且
当前数组的长度>64 时,此时此索引位置上的所有数据改为红黑树存储。
Map中的常用方法:
Map中的遍历操作:
(因为:Map无interator()方法,则需要先变成set或者collection,再调用interator()方法)
遍历key
遍历value
遍历key-value
方式一:
方式二:
Map实现类Hashtable 
Map实现类Properties
1.Properties类时Hashtable的子类,该对象用于处理属性文件
2.由于属性文件李的key、value都是字符串类型,所以Properties里的key和value都是字符串
3.存取数据时,建议使用setProperty(Stirng key,Stirng value)方法和getProperty(Stirng key)
collections工具类的使用:
线程不安全–>线程安全
Collection.synchronizedList()
Collection.synchronizedMap()
工具类中的此方法,可将线程不安全转换成线程安全的。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/154589.html