之前在整理Redis的五大数据结构的时候,其中提到了list、set等知识点的时候,就想起来刚上大学那会的青涩时光,抱着一本Java生啃得时候得傻样,跟女朋友交流的时候,她说那你怎么不也顺便整理一下啊,自己也回想以下那个时候咱俩谈恋爱你让我在机房等你的时候,哼!(ps:我闲的没啥事提这茬干啥啊,先去哄一下再回来继续写啊)

。。。

哄好了,回来继续写,翻出来那个时候整理的笔记,这是我做的思维导图(当时我的导师要求我做的,我感谢他培养了我这个习惯),正好在这里当作目录使用了(后面讲解得时候,我会展开展示)

在学Java以前,一说到存放东西,第一个想到的就是使用数组,使用数组,在数据的存取方面的却也挺方便,其存储效率高访问快,但是它也受到了一些限制,比如说数组的长度以及数组的类型,当我需要一组string类型数据的同时还需要Integer类型的话,就需要定义两次,同时,数组长度也受到限制,即使是动态定义数组长度,但是长度依然需要固定在某一个范围内,不方便也不灵活。

如果说我想要消除上面的这个限制和不方便应该怎么办呢?Java是否提供了相应的解决方法。答案是肯定的,这就是Java容器,java容器是javaAPI所提供的一系列类的实例,用于在程序中存放对象,主要位于Java.util包中,其长度不受限制,类型不受限制,你在存放String类的时候依然能够存放Integer类,两者不会冲突。

容器API类图结果如下所示:

Collection接口

Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素。一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。

举例:

import java.util.*;public class TestA{public static void main(String[] args){Collection lstcoll=new ArrayList();  lstcoll.add("China");  lstcoll.add(new String("ZD"));   System.out.println("size="+lstcoll.size());    System.out.println(lstcoll);}

结果:

List接口

List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,也就是说它是有顺序的,类似于Java的数组。和Set不同,List允许有相同的元素。J2SDK所提供的List容器类有ArrayList、LinkedList等。

实例:

import java.util.*;public class TestB{public static void main(String[] args){List l1=new LinkedList();for(int i=0;i<=5;i++){l1.add("a"+i);}System.out.println(l1);l1.add(3,"a100");System.out.println(l1);l1.set(6,"a200");System.out.println(l1);System.out.println((String)l1.get(2)+" ");l1.remove(1);System.out.println(l1);}}

运行结果:

ArrayList

ArrayList其实就相当于顺式存储,它包装了一个数组 Object[],当实例化一个ArrayList时,一个数组也被实例化,当向ArrayList中添加对象时,数组的大小也相应的改变。这样就带来以下有特点: 快速随即访问,你可以随即访问每个元素而不用考虑性能问题,通过调用get(i)方法来访问下标为i的数组元素。 向其中添加对象速度慢,当你创建数组时并不能确定其容量,所以当改变这个数组时就必须在内存中做很多事情。 操作其中对象的速度慢,当你要向数组中任意两个元素中间添加对象时,数组需要移动所有后面的对象。

下面我们来看一下源码级实际操作

基于数组,支持快速随机访问

public class ArrayList extends AbstractList        implements List, RandomAccess, Cloneable, java.io.Serializable // 实现了RandomAccess表示支持快速随机访问

数组默认大小为10,基于数组实现

private static final int DEFAULT_CAPACITY = 10;transient Object[] elementData; // non-private to simplify nested class access

添加元素时会调用add()方法,同时使用ensureCapacityInternal()方法来保证调用add()方法时数组的容量,当数组容量不够时,会调用grow()方法进行扩容。

扩容代码:

private void grow(int minCapacity) {        // overflow-conscious code        int oldCapacity = elementData.length;        int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容大小为原来的1.5倍       ......      ......// minCapacity is usually close to size, so this is a win:        elementData = Arrays.copyOf(elementData, newCapacity); // 将原来的数组拷贝进新的数组,扩容的代价高    }

删除元素是会调用system.arraycopy()方法,将index+1后面的元素都复制到index的位置上,代价高

System.arraycopy(elementData, index+1, elementData, index, numMoved);

LinkedList

LinkedList相当于链式存储,它是通过节点直接彼此连接来实现的。每一个节点都包含前一个节点的引用,后一个节点的引用和节点存储的值。当一个新节点插入时,只需要修改其中保持先后关系的节点的引用即可,当删除记录时也一样。这样就带来以下特点: 操作其中对象的速度快,只需要改变连接,新的节点可以在内存中的任何地方。 不能随即访问,虽然存在get()方法,但是这个方法是通过遍历接点来定位的,所以速度慢。

代码实现

private static class Node {        E item;        Node next;        Node prev;        Node(Node prev, E element, Node next) {            this.item = element;            this.next = next;            this.prev = prev;        }    }

Set接口

Set是一种不包含重复的元素的Collection,即任意的两个元素e1和e2都有e1.equals(e2)=false,Set最多有一个null元素。 Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。

Set容器类主要有HashSet和TreeSet等。

HashSet

此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。

举例:

import java.util.*;public class TestC{public static void main(String[] args){Set  s=new HashSet();s.add("Hello");        //相同元素s.add("Hello"); System.out.println(s);}

结果:

treeset

TreeSet是一个有序的集合,它的作用是提供有序的Set集合。它继承了AbstractSet抽象类,实现了NavigableSet,Cloneable,Serializable接口。TreeSet是基于TreeMap实现的,TreeSet的元素支持2种排序方式:自然排序或者根据提供的Comparator进行排序。

实例

public static void demoOne() {        TreeSet ts = new TreeSet<>();        ts.add(new Person("张三", 11));        ts.add(new Person("李四", 12));        ts.add(new Person("王五", 15));        ts.add(new Person("赵六", 21));                System.out.println(ts);    }

执行结果:会抛出一个 异常:java.lang.ClassCastException
显然是出现了类型转换异常。原因在于我们需要告诉TreeSet如何来进行比较元素,如果不指定,就会抛出这个异常

如何解决:
如何指定比较的规则,需要在自定义类(Person)中实现Comparable接口,并重写接口中的compareTo方法

public class Person implements Comparable {    private String name;    private int age;    ...    public int compareTo(Person o) {        return 0;                //当compareTo方法返回0的时候集合中只有一个元素        return 1;                //当compareTo方法返回正数的时候集合会怎么存就怎么取        return -1;                //当compareTo方法返回负数的时候集合会倒序存储    }}

为什么返回0,只会存一个元素,返回-1会倒序存储,返回1会怎么存就怎么取呢?原因在于TreeSet底层其实是一个二叉树机构,且每插入一个新元素(第一个除外)都会调用compareTo()方法去和上一个插入的元素作比较,并按二叉树的结构进行排列。

如果将compareTo()返回值写死为0,元素值每次比较,都认为是相同的元素,这时就不再向TreeSet中插入除第一个外的新元素。所以TreeSet中就只存在插入的第一个元素。

如果将compareTo()返回值写死为1,元素值每次比较,都认为新插入的元素比上一个元素大,于是二叉树存储时,会存在根的右侧,读取时就是正序排列的。

如果将compareTo()返回值写死为-1,元素值每次比较,都认为新插入的元素比上一个元素小,于是二叉树存储时,会存在根的左侧,读取时就是倒序序排列的。

Map接口

值得注意的是Map没有继承Collection接口,Map接口是提供key到value的映射。一个Map中不能包含相同的key,每个key只能映射一个value。即是一一映射,Map接口提供3种集合的视图,Map的内容可以被当作一组key集合,一组value集合,或者一组key-value映射。

Map接口的实现类主要是包括HashMap和TreeMap等。

HaspMap

添加数据使用put(key, value),取出数据使用get(key), HashMap是允许null,即null value和null key。但是将HashMap视为Collection时(values()方法可返回Collection),其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的话,不要将HashMap的初始化容量设得过高,或者load factor过低。

举例:

import java.util.*;public class TestD{public static void main(String[] args){Map  M=new HashMap ();M.put("one",new String("1"));M.put("two",new String("2"));System.out.println(M);}}

结果:

ConcurrentHashMap

并发下使用的线程安全的 HashMap 的替代品,基于JDK1.7源码。

数据存储结构,HashMap为Entry。

static final class HashEntry {    final int hash;    final K key;    volatile V value;    volatile HashEntry next;}
  // ConcurrentHashMap 采用了分段锁(Segment)技术,每个分段锁维护着几个桶(HashEntry),多个线程可以同时访问不同分段锁上的桶,Segment[]代替了table[]。final Segment[] segments;//Segment核心类继承自重入锁ReentrantLock。static final class Segment extends ReentrantLock implements Serializable {  // ConcurrentHashMap默认并发级别是16,因为有16个Segmen。  // 默认并发级别为16static final int DEFAULT_CONCURRENCY_LEVEL = 16; 

总结

Java容器实际上只有三种:Map , List, Set;但每种接口都有不同的实现版本.它们的区别可以归纳为由什么在背后支持它们.也就是说,你使用的接口是由什么样的数据结构实现的.


List的选择:

比如:ArrayList和LinkedList都实现了List接口.因此无论选择哪一个,基本操作都一样.但ArrayList是由数组提供底层支持.而LinkedList是由双向链表实现的.所以,如果要经常向List里插入或删除数据,LinkedList会比较好.否则应该用速度更快的ArrayList。

Set的选择
HashSet总是比TreeSet 性能要好.而后者存在的理由就是它可以维持元素的排序状态.所以,如果需要一个排好序的Set时,才应该用TreeSet。

Map选择:
同上,尽量选择HashMap。

其实每一个牵扯到底层得面试题都都不是很难,但是也不能掉以轻心,如果平时没有注意这个地方得知识,那你在面试的时候一定会让你吃亏,这就是开发这一行得魅力,享受这一行得刺激把

java compareto方法怎么排序的_很简单却能让你面试头疼得Java容器,这里从源码给你解释清楚相关推荐

  1. java compareto方法怎么排序的_深入理解Java中Comparable和Comparator排序

    本文有牛旦教育原创,头条首发,转载注明来源. 如何为需要的排序算法选择正确的接口?通过本文的分析讲解,我们会找到答案参考答案. 程序员经常需要将数据库中的元素排序为集合.数组或映射.在Java中,我们 ...

  2. java每轮排序结果_【算法队列面试题】面试问题:java选择题… - 看准网

    1.ArrayList类的底层数据结构是(  ) A.数组结构 B.链表结构 C.哈希表结构 D.红黑树结构 2.LinkedList类的特点是(  ) A.查询快 B.增删快 C.元素不重复 D.元 ...

  3. java断点续传原理_很简单的Java断点续传实现原理

    原理解析 在开发当中,"断点续传"这种功能很实用和常见,听上去也是比较有"逼格"的感觉.所以通常我们都有兴趣去研究研究这种功能是如何实现的? 以Java来说,网 ...

  4. jnlp(Java网络加载协议)原来很简单

    jnlp(Java网络加载协议)原来很简单 Java Network Launching Protocol (JNLP,java网络加载协议). jnlp是什么?是java提供的一种让你可以通过浏览器 ...

  5. Java高并发程序设计学习笔记(五):JDK并发包(各种同步控制工具的使用、并发容器及典型源码分析(Hashmap等))...

    转自:https://blog.csdn.net/dataiyangu/article/details/86491786#2__696 1. 各种同步控制工具的使用 1.1. ReentrantLoc ...

  6. java计算机毕业设计个人连锁民宿信息管理系统设计与开发系统(修改)MyBatis+系统+LW文档+源码+调试部署

    java计算机毕业设计个人连锁民宿信息管理系统设计与开发系统(修改)MyBatis+系统+LW文档+源码+调试部署 java计算机毕业设计个人连锁民宿信息管理系统设计与开发系统(修改)MyBatis+ ...

  7. Java CompareTo方法使用及详解

    compareTo方法有两种: compareTo(String str) 按字典顺序比较两个字符串. compareToIgnoreCase(String str) 按字典顺序比较两个字符串,不考虑 ...

  8. java compareTo 方法 和 Comparator 接口

    compareTo 方法是接口 Comparable 的实现 返回值是整型,它是先比较对应字符的大小(ASCII码顺序),如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的长度差值,如果第 ...

  9. java 分布式任务_一个简单的基于 Redis 的分布式任务调度器 —— Java 语言实现...

    折腾了一周的 Java Quartz 集群任务调度,很遗憾没能搞定,网上的相关文章也少得可怜,在多节点(多进程)环境下 Quartz 似乎无法动态增减任务,恼火.无奈之下自己撸了一个简单的任务调度器, ...

最新文章

  1. 诗歌rails之 有条件的validation
  2. 【杂谈】如何学会看arxiv.org才能不错过自己研究领域的最新论文?
  3. mysql附加服务器失败_今天,启动MySQL服务器失败,
  4. layui 行悬停显示工具_Minitab | 工具栏和状态栏
  5. [iPhoneアプリ]iEscaper2攻略その6|龍の水晶
  6. flask第一章:项目环境搭建
  7. 杭电 1021 找规律
  8. Python sys.path、sys.modules模块介绍
  9. Matlab绘制曲线
  10. HBase Rowkey的散列与预分区设计
  11. 夜神模拟器安装frida-server图文详解
  12. 文物摄影中白平衡的正确设置(图)
  13. matlab在c盘有缓存文件夹吗,win10如何清除C盘缓存文件-win10清除C盘缓存的方法 - 河东软件园...
  14. java虚拟机运行机制
  15. Mac苹果移动硬盘数据丢失怎么恢复?
  16. 调用其他命名空间中的函数-洋葱先生-杨少通
  17. PyCharm 4.5 激活码
  18. web实验报告——JSP动态网页编程
  19. scrapy 爬取苏宁图书
  20. 大数据安全分析平台评估五要素

热门文章

  1. dw1000 github_GitHub打破了我的1000天连胜纪录
  2. 133_Power BI 报表服务器2020年1月版本更新亮点
  3. Clion配置Toolchains
  4. 记一些Python(Pymysql)建表、增删改查等基础操作(小白适用)
  5. 进程的创建-Process子类(python 版)
  6. Hive 内置函数权威指南,操作大全
  7. Visual Studio 2010 实用功能总结图解
  8. ASP.NET中Request.ApplicationPath、Request.FilePath、Request.Path、.Request.MapPath、Server.MapPath的区别
  9. 石油-美元金融体系的形成
  10. 漫步数理统计四——概率集合函数(下)