Java程序员秋招复习冲刺day03

2.1集合

	Java的集合类被定义在Java.util包中,主要分为两类:Collection、Map,其次又可以被分为List、Queue、Set和Map四类集合

Collection集合主要用来存储的是独立的元素,其中set、list和Queue,其中list是按照插入的顺序保存元素,而set中则不能有重复的元素,而Queue按照排队规则来处理容器中的元素。Map的则是用来存储<键,值>对,这个容器允许通过键来查找值。

List集合:ArrayList、LinkedList和Vector

Queue:ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、DelayQueue、SynchronousQueue、LinkedTransferQueue、LinkedBlockingQueue

Set:HashSet、TreeSet和LinkedHashSet

Map:HashMap、HashTable、TreeMap

2.1.1 List:可以重复的集合

List是一种线性的列表结构,它继承自Collection接口,是一种有序集合,List中的元素可以根据索引进行检索、删除或者插入操作。在Java中List接口中主要以下常用的List实现类。

1.ArrayList:基于数组实现的,查询快、增删慢,线程不安全

ArrayList是用数组来实现的List,主要提供了对List的增加add、删除remove和访问get功能。其主要的特点是随机访问效率高(相对于顺序访问来说),读快写慢(主要由于写的过程中需要涉及元素的移动,因此写操作的效率比较低)

ArrayList的缺点是对元素必须连续存储,因此ArrayList不适合随机插入和删除的操作,更适合随机查找和遍历的操作

ArrayList不需要再定义时指定数组的长度,在数组长度不能满足存储要求时,ArrayList会创建一个更大的数组并将数组中已有的数据复制到新的数组中

	ArrayList的实现原理

(1)父类和接口

	java.util.AbstractList.该抽象类是大部分List的共同子类,它提供了一些基本的方法以及通用迭代器的实现

	java.util.List。列表标准接口,列表是一个有序集合,又被称为序列,该忌口对它内部的每一个元素的插入位置都有精确控制,用户可以使用整数索引来查询

	java.util.RandomAccess.这是一个标记性质的随机访问接口,它没有提供任何方法。如果一个类实现了这个接口,那么表示这个类使用索引遍历比迭代器要更快

	java.lang.Cloneable。用于标记可克隆对象,是一个常见接口,没有实现该接口的对象在调用Object.clone()方法时会抛出异常

	java.io.Serializable。序列化标记接口,是一个常见接口,被此接口标记的类可以实现Java序列化和反序列化。该接口没有任何内容。

(2)成员变量和常量

	ArrayList有三个重要多的成员和两个常量

	1)成员变量

	private transient Object[] elementData,elementData是该List的数据域,其中被transient修饰表示这个变量不会被序列化,它提供给Serializable接口使用

	private int size,size表示当前List的长度,需要注意的是,elementData的length必然是大于或等于size的。这是因为elementData是存放数据的数组提供了size变量来标识真正的List的大小

	protected transient int modCount=0,该成员变量继承自AbstractList,记录了ArrayList结构性变化的次数。

	2)常量

	private static final long serialVersionUID=2343424244L

	序列化版本UID,根据这个名字能判断出它是提供给序列化接口使用的,该UID是为了维持序列化版本一致性的	

	private static final int Max——ARRAY_SIZE=Integer.MAX_VALUE-8

	数组长度的上限,这里设置的是最大整数-8

Vector:基于数组实现的,增删慢、查询快,线程安全

	Vector的实现与ArrayList基本是一致的,都是基于数组实现的,不同的是Vector支持线程同步,即同一时刻只允许一个线程对Vector进行写操作,以保证多线程环境下数据的一致性,但需要频繁地对Vector实例进行加锁和释放锁操作,因此Vector的读写效率在整体上比ArrayList低。

	Vector所有的public方法是使用synchronized关键字,Vector多了一个成员变量capacityIncrement,用于标明扩容的增量,与ArrayList固定扩容50%相比,Vector根据capacityIncrement的数值来扩容

	需要注意的是stack是Vector的子类,因此它的实现和Vector是一致的

LinkedList:基于双向列表实现的,增删快,查询慢,线程不安全

	LinkedList采用双向链表结构存储元素,在对LinkedList进行插入和删除操作时,只需要在对应的节点上插入或删除元素,并将上一个节点的下一个节点的指针指向该节点即可,数据改动比较小,因此随机插入和删除效率很高。但是在对LinkedList进行随机访问时,需要从链表头部一直遍历到该节点位置,因此随机访问很慢。初次以外,LinkedList还提供了在List接口未定义的方法,用于操作链表头部和尾部的元素,因此有时可以被当做堆栈、队列和双向队列使用

2.1.2 Queue

	Queue是队列结构,本身是一种先入先出的模型,Queue是一个接口,有的类采用线性表来实现的,有的则基于链表实现的,有些类是多线程安全的,有些则不是。

PriorityBlockingQueue:基于优先级排序的无界阻塞队列

	该队列并不遵循陷入先出的原则,它会根据队列元素的优先级来调整顺序,优先级最高的元素最先出,PriorityQueue提供了一个comparator成员变量来对元素进行比较

	transient Object[] queue;//存储数组

	privateint size =0;//元素数量

	private final Comparator<? super E> comparator;//比较器

ArrayBlockingQueue:基于数组结构实现的有界阻塞队列

LinkedBlockingQueue:基于链表数据结构的有界阻塞队列

DelayQueue:支持延迟操作的无界阻塞队列

SynchronousQueue:用于线程同步的阻塞队列

LinkedTransferQueue:基于链表数据结构实现的无界阻塞队列

LinkedBlockingDeque:基于链表数据结构实现的双向阻塞队列

2.1.3 Set:不可重复的集合

	Set的核心是独一无二的性质,适用于存储无序且值不相等的元素。对象的相等性本质上是对象的HashCode值相同,Java依据对象的内存地址计算出对象的HashCode值。如果想要比较两个对象是否相等,则必须同时覆盖对象的hashCode方法和equal方法,并且hashCode方法和equals方法的返回值必须相同

	1.HashSet:HashTable实现,无序

	HashSet存放的是散列值,它是按照元素的散列值来存取元素的。元素的散列值是通过hashCode方法计算得到的,HashSet首先判断两个元素的散列值是否相当,如果散列值相等,则接着通过equals方法进行比较,如果equals方法返回的结果也为true,HashSet就将其视为同一个元素;如果equals方法返回的结果为false,HashSet就不将其视为同一个元素

	2.TreeSet:二叉树实现

	TreeSet基于二叉树的原理对新添加的元素按照指定的顺序排序,每添加一个对象都会进行排序,并将对象插入指定的位置。

	Integer和String等基础对象类型可以直接根据TreeSet的默认排序进行存储,而自定义的数据类型必须实现Comparable接口,并且覆写其中的compareTo函数才可以按照预定义的顺序存储。若覆写compare函数,则在升序时在this.对象小于指定对象的条件下返回-1

	3.LinkHashSet:HashTable实现数据存储,双向链表记录顺序

	LinkedHashSet在底层使用额LinkedHashMap存储元素,它继承了HashSet,所有的方法和操作都与HashSet相同,因此其实现比较简单,只提供了四个构造方法,并通过传递一个标识参数调用父类的构造器,在底层构造一个LinkedHashMap来记录数据访问,其它相关操作与父类HashSet相同,直接调用父类多的HashSet的方法即可

2.1.4 Map

	Map是一种由多组key-value(键值对)集合在一起的结构,其中key值是不能重复的,而value值则无此限定。

HashMap

	HashMap是最长用的Map结构,Map的本质是键值对。它使用数组来存放这些键值对,HashMap基于键的HashCode值唯一标识一条数据,同时基于键的HashCode值进行数据的存取,因此可以快读地更新和查询数据,但其每次遍历的顺序无法保证相同。HashMap的key和value允许为null

	在HashMap中,当且仅当hashCode一致且equals比对一致的对象才会被认为是同一个对象

Java8之前的HashMap

HashMap的底层实现是数组和链表

	(1)成员变量

	transient  Entry<K,V> [] table;//存储数据的核心成员变量

	transient  int size;//HashMap中键值对的数量

	final float loadFactor;//加载因子,用于决定table的扩容量

table是HashMap的核心成员变量,该数组用于记录HashMap的所有数据,它的每一个下标都对应一条链表,换言之所有哈希冲突的数据都会被存放到同一条链表中。Entry<K,V>则是该链表的节点元素

final K key存放键值对中的关键字

V value存放键值对中的值

Entry<K,V> next指向下一个节点的引用

int hash key所对应的hashcode

HashMap的核心实现就是一个单向链表数组(Entry<K,V>[] table),HashMap规定了该数组的两个特性:

1)会在特定时刻根据需要来扩容2)其长度始终保持为2的幂次方

思考一个问题,如果一个Object的对象对应的hashcode为51,上面有个字符串同时存入HashMap值也是51,那在存入的时候会怎么处理/

答案是它会被存入链表里和之前的字符串同时存在,当需要查找指定的对象的时候,首先会找到hashcode 的下标,然后遍历链表,调用对象的equals方法进行比对从而找到对应的对象。

由于数组的查找是比链表要快的,因此尽可能使得键值的hashcode分散,这样就可以提高hashmap的查询效率

HashMap是非线程安全的,即在同一时刻有多个线程同时写HashMap时将可能导致数据的不一致。如果需要满足线程安全的条件,则可以使用Collections的synchronizedMap方法使得HashMap具有线程安全的能力,或者使用ConcurrentHashMap

为了减少链表遍历的开销,Java8对HashMap进行了优化,将数据结构修改为数组加链表或红黑树。在链表结构中的元素超过8个以后,HashMap会将链表结构转换为红黑树结构以提高查询效率,因此其时间复杂度为O(logN)

在Java8中数据类型发生了变化,代表的链表节点的Entry<K,V>换成了Node<K,V>,Node本身具备链表节点的特性,同时它还有一个子类TreeNode<K,V>,从名字可以看出是一个树节点

ConcurrentHashMap:分段锁实现,线程安全

	与HashMap不同是ConcurrentHashMap采用分段锁的思想实现并发操作,因此是线程安全的。ConcurrentHashMap由多个Segment组成(Segment的数量也是锁的并发度),每个Segment均继承自ReentrantLock并单独加锁,所以每次进行加锁操作时锁住的都是一个Segment,这样也就保证每个Segment都是线程安全的,也就实现了全局的线程安全。



在ConcurrentHashMap中有个concurrencyLevel参数表示并行级别,默认是16,也就是说ConcurrentHashMap默认由16个Segments组成,在这种情况下最多同时支持16个线程并发执行写操作,只要它们的操作分布在不同的Segment上即可。并行级别concurrencyLevel可以在初始化时设置,一旦初始化就不可更改。ConcurrentHashMap的每个内部的数据结构都和HashMap相同。

Java 8中在ConcurrentHashMap中引入了红黑树

HashTable:线程安全

HashTable的实现与HashMap很类似,整体流程也是没有太大的变化的,不同的是它继承自Dictionary类,并且是线程安全的,同一时刻只有一个线程能写HashTable,并发性不如ConcurrentHashMap

从源码可以看出HashTable的实现方式被synchronized修饰,由此可见HashTable是线程安全的,而HashMap是线程不安全的;此外Hashtable不能存放null作为key值

虽然HashTable是线程安全的但是在多线程环境下并不推荐使用。因为采用synchronized方式实现的多线程安全的容器在大并发量的情况下效率比较低下

TreeMap:基于二叉树数据结构

TreeMap基于二叉树数据结构存储数据,同时实现了SortedMap接口以保障元素的顺序存取,默认按键值的升序排序,也可以自定义排序比较器

TreeMap常用于实现排序的映射列表。在使用TreeMap时其key必须实现Comparable接口采用自定义的比较器,否则会抛出java.lang.ClassCastException异常

LinkedHashMap:基于HashTable数据结构,使用链表保存插入顺序

LinkedHashMap为HashMap的子类,其内部使用链表保存元素的插入顺序,在通过Iterator遍历LinkedHashMap时,会按照元素的插入顺序访问元素。LinkedHashMap主要有两个成员变量需要注意

private transient Entry<K,V> header;

private final boolean accessOrder;//true为顺序访问,false为逆序

LinkedHashMap中包含了一个额外的双向链表结构,header既是头又是尾,可以视作一个环状链表,LinkedHashMap可以像HashMap一样的使用,同时它为每个数据结点的引用多维护一个链表,从而可以达到有序访问的目的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值