不知你是否还记得高中我们学过的集合,映射,函数,数学确实很牛逼,拿它来研究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. css3中animation属性animation-timing-function知识点以及其属性值steps()

    在animation中最重要的其实就是时间函数(animation-timing-function)这个属性,他决定了你的动画将以什么样的速度执行,所以最关键的属性值也就是cubic-bezier(n ...

  2. ios之coredata(二)

    上面一篇文章介绍了coredata的有关基本概念,由于大部分是参考别人文章中的内容,所以感觉有点虚,而且估计也是比较难以理解,下面这篇文章通俗一点说说学习coredata后的一些理解,然后给出一个简单 ...

  3. CentOS7服务器上部署Oracle客户端

    环境 操作系统: CentOS7.2.1511 x86_64 准备安装包 在这个网站:https://www.oracle.com/technetwork/topics/linuxx86-64soft ...

  4. Idea 搭建Maven--web项目(MVC)

    小编最近正在学习使用MVC框架,在搭建Maven的项目过程中,遇到了很多问题,上网搜了很多材料才找到答案,为了小编以后查起来方便,也为了向广大小伙伴分享,写了这部片博文,敬我昨天一天的学习结果! 步骤 ...

  5. kill, killall, pkill, xkill

    1. Kill Command – Kill the process by specifying its PID All the below kill conventions will send th ...

  6. 我的Python分析成长之路4

    一.函数 1.什么是函数?:函数是带名字的代码块,调用函数,只要调用函数名就可以.    2.函数的性质:1.减少重复代码 2.使程序变得可扩展 3.使程序变得易维护 3.编程范示: 1.面向对象编程 ...

  7. LeetCode101--对称二叉树

    ''' 给定一个二叉树,检查它是否是镜像对称的. ''' class TreeNode: def __init__(self, x): self.val = x self.left = None se ...

  8. git commit 含有中文的代码,提示Warnning:Your console font probably doesn't support Unicode.......

    git 提交代码是会遇到以下问题, git commit 代码时提示: Warning: Your console font probably doesn't support Unicode. If ...

  9. python基础学习笔记——初识函数

    什么是函数 我们目前为止,已经可以完成一些软件的基本功能了,那么我们来完成这样一个功能:约x 1 2 3 4 5 pint("拿出手机") print("打开陌陌&quo ...

  10. linux -- 查找(find)命令 一

    find: find命令是非常有用的linux命令,我们可以用它来根据指定的搜索条件来搜索整个文件系统来查找文件或目录. 基本的‘find file’命令 find . -name "foo ...