不知你是否还记得高中我们学过的集合,映射,函数,数学确实很牛逼,拿它来研究java集合类,轻而易举的就把知识理解了。本篇文章适合初学java集合类的小白,也适合补充知识漏缺的学习者,同时也是面试者可以参考的一份资料。

数学知识

回顾一下之前所学的知识,结合我多年的高中数学教学经验,相信你会对某些知识有一些新的感悟。

集合:一般地,我们把研究对象统称为元素(element),把一些元素组成的总体叫做集合(set)。

对于一个给定的集合,其具有的特征:

确定性:集合中的元素都是确定的。

互异性:集合中的元素都是不同的。

无序性:集合中的元素的顺序是无序的。

映射:一般地,我们有:

设A,B是两个非空的集合,如果按照某一个确定的对应关系f.是对应集合A中的任意一个元素x,在集合B中都有唯一确定的元素y与之对应,那么就称对应f:A—>B为集合A到集合B的一个映射(mapping)。

其实简单的来讲,何谓映射,就是函数上将的关系对应,例如:

函数 f(x)=x^2  那么每一个x都有唯一的y与之对应,这就是映射关系的一个模型。

而方程 x^2+y^2=1,这个很明显是圆心为(0,0)的半径为1的圆,任取一个x可能会有一个或者两个y与之对应,这就不能称为映射,进而不能称为函数。(1,0)或者(-1,0)这时候的x只有唯一的确定的y和它对应。

集合类的学习

集合类产生的原因:在一般的情况下,我们在写程序时并不知道将需要多少个对象,或者是否需要更加复杂的方式存储对象,显然使用具有固定长度的数组已经不能解决这个问题了。所以java 实用类库提供了一套相当完整的容器类来解决这个问题。

基本概念

java容器类类库的用途是“保存对象”,可将其划分为两个不同的概念:

1)collection.独立元素的序列。主要包含List(序列),Set(集合),Queue(队列)

List:按照插入的顺序保存元素;

Set:不能有重复的元素;

Queue:按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同);

2)Map:一组成对的“键值对”对象,允许我们使用键来查找值。

针对经常使用的类库,我们只列出List,Set,Map之间的继承关系:

List

List接口在Collection的基础上添加了大量的方法,使得可以在List的中间插入和删除元素。

继承自List的子类有ArrayList,   LinkedList ,Vector三类。

list的特征:

 有序的Collection
允许重复的元素,允许空的元素。
插入类似的数据:{1,2,4,{5,2},1,3};

ArrayList(类似于顺序表)

其主要用于查找,对于删除和插入,耗时巨大。ArrayList是以数组实现的列表,不支持同步。

优点:利用索引位置可以快速的定位访问

适合变动不大,主要用于查询的数据

和java的数组相比较,其容量是可以动态调整的。

缺点:不适合指定位置的插入,删除操作。

--ArrayList在元素填满容器是会自动扩充容器大小的50%

ArrayListTest 代码分析:

add()方法,添加元素,默认是在后面添加。

add(index,value),在指定索引处添加元素。会进行元素的移动。源码如下:

 public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}

remove(index)删除指定位置上的元素。源码如下:

 public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}

  从源码可以分析出,在ArrayList进行插入和删除的时候,会进行类似顺序表的操作,移动元素,空出位置,然后插入元素。删除:依次移动后面的元素覆盖指定位置的元素。这就会大大减慢ArrayList插入和删除的效率。

举一个应用的例子,更好的理解ArrayList:

 public class ArrayListTest {
public static void main(String[] args) {
//泛型的用法,只允许Integer类型的元素插入。
ArrayList<Integer> arrayList =new ArrayList<Integer>();
//增加元素
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
arrayList.add(5);
arrayList.add(4);
arrayList.add(null);//ArrayList允许空值插入,
arrayList.add(new Integer(3));
System.out.println(arrayList);// [2, 3, 4, 5, 4, null, 3]
//查看元素的个数
System.out.println(arrayList.size());//
arrayList.remove(0);
System.out.println(arrayList);// [3, 4, 5, 4, null, 3]
arrayList.add(1, new Integer(9));
System.out.println(arrayList);// [3, 9, 4, 5, 4, null, 3]
System.out.println("-----------遍历方法-------");
ArrayList<Integer> as=new ArrayList<Integer>(100000);
for(int i=0;i<100000;i++){
as.add(i);
}
traverseByIterator(as);
traverseByFor(as);
traverseByForEach(as);
}
public static void traverseByIterator(ArrayList<Integer>al){
System.out.println("---------迭代器遍历-------------");
long startTime=System.nanoTime();//开始时间
Iterator it=al.iterator();
while(it.hasNext()){//
it.next();
}
long endTime=System.nanoTime();//结束时间
System.out.println((endTime-startTime)+"纳秒");
}
public static void traverseByFor(ArrayList<Integer>al){
System.out.println("---------索引遍历-------------");
long startTime=System.nanoTime();//开始时间
for(int i=0;i<al.size();i++) al.get(i);
long endTime=System.nanoTime();//结束时间
System.out.println((endTime-startTime)+"纳秒");
}
public static void traverseByForEach(ArrayList<Integer>al){
System.out.println("---------Foreach遍历-------------");
long startTime=System.nanoTime();//开始时间
for(Integer temp:al);
long endTime=System.nanoTime();//结束时间
System.out.println((endTime-startTime)+"纳秒");
}
}
-----------遍历方法-------
---------迭代器遍历-------------
10407039纳秒
---------索引遍历-------------
7094470纳秒
---------Foreach遍历-------------
9063813纳秒
可以看到利用索引遍历,相对来说是快一些。

迭代器 Iterator

 hasNext()  判断是否有下一个元素
next() 获取下一个元素
remove () 删除某个元素

LinkedList:(主要用于增加和修改!)

--以双向链表实现的列表,不支持同步。

--可以被当做堆栈、队列和双端队列进行操作

--顺序访问高效,随机访问较差,中间插入和删除高效

--适合经常变化的数据

addFirst()在头部添加元素

add(3,10);将10插入到第四个位置上

remove(3)删除第四个位置的元素

代码详解:

 public class LinkedListTest {
public static void main(String[] args) {
LinkedList<Integer> linkedList=new LinkedList<Integer>();
linkedList.add(2);
linkedList.add(3);
linkedList.add(9);
linkedList.add(6);
linkedList.add(7);
System.out.println(linkedList);
//linkedList.addFirst(1);
//linkedList.addLast(10);
//System.out.println(linkedList);
linkedList.add(3, 4);
System.out.println(linkedList);
System.out.println(linkedList.get(4));
LinkedList<Integer> as=new LinkedList<Integer>();
for(int i=0;i<100000;i++){
as.add(i);
}
traverseByIterator(as);
traverseByFor(as);
traverseByForEach(as);
}
public static void traverseByIterator(LinkedList<Integer>al){
System.out.println("---------迭代器遍历-------------");
long startTime=System.nanoTime();//开始时间
Iterator it=al.iterator();
while(it.hasNext()){
it.next();
}
long endTime=System.nanoTime();//结束时间
System.out.println((endTime-startTime)+"纳秒");
}
public static void traverseByFor(LinkedList<Integer>al){
System.out.println("---------索引遍历-------------");
long startTime=System.nanoTime();//开始时间
for(int i=0;i<al.size();i++) al.get(i);
long endTime=System.nanoTime();//结束时间
System.out.println((endTime-startTime)+"纳秒");
}
public static void traverseByForEach(LinkedList<Integer>al){
System.out.println("---------Foreach遍历-------------");
long startTime=System.nanoTime();//开始时间
for(Integer temp:al);
long endTime=System.nanoTime();//结束时间
System.out.println((endTime-startTime)+"纳秒");
}
}
---------迭代器遍历-------------
6562423纳秒
---------索引遍历-------------
4565606240纳秒
---------Foreach遍历-------------
4594622纳秒
可以看出使用索引遍历,对于linkedList真的很费时间!

add(index,value)源码分析:我们可以看到,这就是双引用(双指针)的赋值操作。

 void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}

remove(index)源码分析:同样,这也是对引用的更改操作,方面多了!

 E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev; if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
} if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
} x.item = null;
size--;
modCount++;
return element;
}

get(index)源码分析:利用指针挨个往后查找,直到找到位置为index的元素。当然了,找的时候也是要注意方法的,比如说利用二分查找。

 Node<E> node(int index) {
// assert isElementIndex(index); if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}

Vector

-和ArrayList类似,可变数组实现的列表

-Vector同步,适合在多线程下使用

-原先不属于JCF框架,属于java最早的数据结构,性能较差

-从JDK1.2开始,Vector被重写,并纳入JCF中

-官方文档建议在非同步的情况下,优先采用ArrayList

其实vector类似于ArrayList,所以在一般情况下,我们能优先使用ArrayList,在同步的情况下,是可以考虑使用Vector

代码例子:

 public class VectorTest {
public static void main(String[] args) {
Vector<Integer> vs=new Vector<Integer>();
vs.add(1);
vs.add(4);
vs.add(3);
vs.add(5);
vs.add(2);
vs.add(6);
vs.add(9);
System.out.println(vs);
System.out.println(vs.get(0));
vs.remove(5);
System.out.println(vs);
/*Integer []a=new Integer[vs.size()];
vs.toArray(a);
for(Integer m:a){
System.out.print(m+" ");
}*/
Vector <Integer> as=new Vector <Integer>(100000);
for(int i=0;i<1000000;i++){
as.add(i);
}
traverseByIterator(as);
traverseByFor(as);
traverseByForEach(as);
traverseEm(as);
}
public static void traverseByIterator(Vector<Integer>al){
System.out.println("---------迭代器遍历-------------");
long startTime=System.nanoTime();//开始时间
Iterator it=al.iterator();
while(it.hasNext()){
it.next();
}
long endTime=System.nanoTime();//结束时间
System.out.println((endTime-startTime)+"纳秒");
}
public static void traverseByFor(Vector<Integer>al){
System.out.println("---------索引遍历-------------");
long startTime=System.nanoTime();//开始时间
for(int i=0;i<al.size();i++) al.get(i);
long endTime=System.nanoTime();//结束时间
System.out.println((endTime-startTime)+"纳秒");
}
public static void traverseByForEach(Vector<Integer>al){
System.out.println("---------Foreach遍历-------------");
long startTime=System.nanoTime();//开始时间
for(Integer temp:al){
temp.intValue();
}
long endTime=System.nanoTime();//结束时间
System.out.println((endTime-startTime)+"纳秒");
}
public static void traverseEm(Vector<Integer>al){
System.out.println("---------Enumeration遍历-------------");
long startTime=System.nanoTime();//开始时间
for(Enumeration <Integer> ei=al.elements();ei.hasMoreElements();){
ei.nextElement();
}
long endTime=System.nanoTime();//结束时间
System.out.println((endTime-startTime)+"纳秒");
}
}
---------迭代器遍历-------------
28927404纳秒
---------索引遍历-------------
32122768纳秒
---------Foreach遍历-------------
25191768纳秒
---------Enumeration遍历-------------
26901515纳秒
可以看到Foreach遍历要快于其他的遍历方法。

add(index,value)源码剖析:这个和ArrayList类似,需要进行元素的复制,所以很慢

 public synchronized void insertElementAt(E obj, int index) {
modCount++;
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
ensureCapacityHelper(elementCount + 1);
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
elementData[index] = obj;
elementCount++;
}

get(index)源码剖析:可以看到,直接根据元素的下表返回数组元素。非常快!

 public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index); return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}

其实List这部分内容用的数学知识不是很多,但是set和Map确实是类似于数学模型的概念。期待后续Set,Map的学习。

个人微信公众号

数学知识巧学JCF(Java Collections framework)的更多相关文章

  1. Java入门系列(七)Java 集合框架(JCF, Java Collections Framework)

    Java 集合概述 List.Set.Map可以看做集合的三大类 java集合就像一个容器,可以将多个对象的引用丢进该容器中. Collection和Map是java集合的根接口. List List ...

  2. (一)一起学 Java Collections Framework 源码之 概述

    . . . . . 目录 (一)一起学 Java Collections Framework 源码之 概述 JDK 中很多类 LZ 已经使用了无数次,但认认真真从源码级研究过其原理的还只占少数,虽然从 ...

  3. (二)一起学 Java Collections Framework 源码之 AbstractCollection

    . . . . . 目录 (一)一起学 Java Collections Framework 源码之 概述(未完成) (二)一起学 Java Collections Framework 源码之 Abs ...

  4. Java Collections Framework概览

    本文github地址 概览 容器,就是可以容纳其他Java对象的对象.Java Collections Framework(JCF)为Java开发者提供了通用的容器,其始于JDK 1.2,优点是: 降 ...

  5. Java Collections Framework Java集合框架概览

    Java SE documents -- The Collections Framework http://docs.oracle.com/javase/8/docs/technotes/guides ...

  6. Java Collections Framework 汇总

    1. Java Collections Framework Java集合框架概览 2. Java Collections Framework 之 RandomAccess接口 3. 关于ArrayLi ...

  7. Java Collections Framework知识结构目录

    The core collection interfaces are the foundation of the Java Collections Framework. The Java Collec ...

  8. 【DataStructure】The description of Java Collections Framework

    The Java Connections FrameWork is a group of class or method and interfacs in the java.util package. ...

  9. Java Collections Framework

    集合OR 容器 通常我们会用数组去保存一些基本数据类型,数组是编译器支持的类型,但是数组的一个明显缺点就是具有固定尺寸,而在一般情况下,只有在程序运行的时候,我们才能知道要保存的具体数目. Java类 ...

随机推荐

  1. CPP-网络/通信:SOCKET

    客户端实现代码: //引入头文件 #include <WinSock2.h> //客户端创建Socket////////////////////////////////////////// ...

  2. 精选30道Java笔试题附答案分析

    精选30道Java笔试题解答 都是一些非常非常基础的题,是我最近参加各大IT公司笔试后靠记忆记下来的,经过整理献给与我一样参加各大IT校园招聘的同学们,纯考Java基础功底,老手们就不用进来了,免得笑 ...

  3. ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded: /usr/lib64/mysql/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory

    部署docker下的mysql时出现以下报错 [root@docker ~]# mysql -h192.168.30.22 -uroot -p Enter password: 出现报错: ERROR ...

  4. 安装pycharm 2018.3 Professional Edition

    1.下载pycharm 2018.3 Professional 2.下载破解补丁,Gitee仓库 或 直接下载(Direct download link) ,并放到pycharm目录下的\bin目录( ...

  5. tableview和searchbar的适配

    iOS7中,如果用UITableViewStyleGrouped的话,里面的 cell会比原来的拉长了,这样做应该是为了统一和UITableViewStylePlain风格时cell的大小一致,所以改 ...

  6. (9)zabbix创建监控项item

    1. 创建监控项 点击配置(configuration)->主机(Hosts)->在你要配置的主机一栏上点击Items->点击create item.具体看截图,各个参数我都已经标注 ...

  7. 蓝牙学习(2)USB Adapter

    主要分析一下蓝牙USB Adapter使用USB接口传输HCI包的实现及过程. 参照上面的Bluetooth core system architecture图, 蓝牙USB Adapter作为Blu ...

  8. Django ORM (一) 创建数据库和模型常用的字段类型参数及Field 重要参数介绍

    创建一个 Django 项目及应用 django-admin startproject orm cd orm python manage.py startapp app01 在 models.py 上 ...

  9. Python9-内置函数2-day16

    #zip方法 l = [1,2,3] l2 = ['a','b','c'] l3 = ('*','**',[1,2]) l4 = {'k1':1,'k2':2} for i in zip(l,l2,l ...

  10. CentOS安装mysql5.6

    1. 去官网https://dev.mysql.com/downloads/mysql/5.6.html下载mysql压缩包,选第一个,最大最全的 2. 通过FTP工具比如FileZila存放到目标地 ...