Ch02-Java Map 之 LinkedHashMap
February 13, 2017
LinkedHashMap 是 HashMap 的直接子类,二者唯一的区别是 LinkedHashMap 在 HashMap 的基础上,采用双向链表 (doubly-linked list) 的形式将所有 entry 连接起来,这样是为保证元素的迭代顺序跟插入顺序相同。
...LinkedHashMap 是 HashMap 的直接子类,二者唯一的区别是 LinkedHashMap 在 HashMap 的基础上,采用双向链表 (doubly-linked list) 的形式将所有 entry 连接起来,这样是为保证元素的迭代顺序跟插入顺序相同。
...1. 底层数据结构 # Java 1.7 中使用数组+链表这样的数据结构,自 Java 1.8 开始使用数组+链表+红黑树这样的数据结构。 2. 数组扩容 # resize() 方法用于初始化数组或数组扩容,每次扩容后,容量为原来的 2 倍,并进行数据迁移。 3.线程不安全 # HashMap 的线程不安全主要体现在下面两个方面: 在 Java 1.7 中,当并发执行扩容操作时会造成环形链。 这里主要的原因是线程1上线文中保存的指针指向的数据(newtable,临界资源)被线程2做了修改,当线程1重新恢复上线文后,在已经被修改的数据(newtable,临界资源)上继续未完成的操作,最终导致结果不符合预期。 在 Java 1.8 中,在并发执行 put 操作时会发生数据覆盖的情况。 4. 参考文献 # HashMap为什么在多线程操作下不安全(jdk1.7和jdk1.8原因不同)
优先队列的作用是能保证每次取出的元素都是队列中权值最小的,这里牵涉到了大小关系,元素大小的评判可以通过元素本身的自然顺序,也可以通过构造时传入的比较器 Comparator。
...Java 里有一个叫做 Stack 的类,却没有叫做 Queue 的类 (它是个接口名字)。当需要使用栈时,Java 已不推荐使用 Stack,而是推荐使用更高效的 ArrayDeque;既然 Queue 只是一个接口,当需要使用队列时也就首选 ArrayDeque 了 (次选是 LinkedList)。
...LinkedList 同时实现了 List 接口和 Deque 接口,也就是说它既可以看作一个顺序容器,又可以看作一个队列 (Queue),同时又可以看作一个栈 (Stack)。所以当需要使用栈或者队列时,可以考虑使用 LinkedList。
...ArrayList 实现了 List 接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入 null 元素,底层通过数组实现。除该类未实现同步外,其余跟 Vector 大致相同。
...集合类 说明 TreeSet 基于红黑树实现,支持有序性操作,例如根据一个范围查找元素的操作。但是查找效率不如 HashSet,HashSet 查找的时间复杂度为 O(1),TreeSet 则为 O(logN)。 HashSet 基于哈希表实现,支持快速查找,但不支持有序性操作。并且失去了元素的插入顺序信息,也就是说使用 Iterator 遍历 HashSet 得到的结果是不确定的。 LinkedHashSet 具有 HashSet 的查找效率,且内部使用双向链表维护元素的插入顺序。 ArrayList 基于动态数组实现,支持随机访问。 Vector 和 ArrayList 类似,但它是线程安全的。 LinkedList 基于双向链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。不仅如此,LinkedList 还可以用作栈、队列和双向队列。 PriorityQueue 基于堆结构实现,可以用它来实现优先队列。 TreeMap 基于红黑树实现。 HashMap 基于哈希表实现。 HashTable 和 HashMap 类似,但它是线程安全的,这意味着同一时刻多个线程可以同时写入 HashTable 并且不会导致数据不一致。 LinkedHashMap 使用双向链表来维护元素的顺序,顺序为插入顺序或者最近最少使用 (LRU) 顺序。
synchronized 是 Java 中的一个关键字,主要用于解决 Java 中常见的并发问题(原子性,可见性,有序性)。
...1. 泛型机制 # 泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。 2. 注解机制 # 注解是 JDK1.5 版本开始引入的一个特性,用于对代码进行说明,可以对包、类、接口、字段、方法参数、局部变量等进行注解。它主要的作用有以下四方面: 生成文档,通过代码里标识的元数据生成 javadoc 文档。 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。 运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例。 3. 异常机制 # 4. 反射机制 # RTTI(Run-Time Type Identification)运行时类型识别。利用反射技术可以对一个类进行解剖,把每个组成部分映射成一个个对象(比如成员变量,方法,构造方法等都可以映射成对象)。 5. SPI 机制 # SPI(Service Provider Interface),是 JDK 内置的一种 服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用。Java 中 SPI 机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是解耦。
1. a==b和a.equals(b)有什么区别? # 如果 a 和 b 都是对象,则 a==b 是比较两个对象的引用,只有当 a 和 b 指向的是堆中的同一个对象才会返回 true,而 a.equals(b) 是进行逻辑比较,所以通常需要重写该方法来提供逻辑一致性的比较。例如,String 类重写 equals() 方法,所以可以用于两个不同对象,但是包含的字母相同的比较。 2. a.hashCode() 有什么用?与 a.equals(b) 有什么关系? # hashCode() 方法是相应对象整型的 hash 值,根据 Java 规范,两个使用 equals() 方法来判断相等的对象,其 hash code 必须相等。 3. final、finalize 和 finally 的不同之处? # 条目 说明 final 是一个修饰符,可以修饰变量、方法和类。如果 final 修饰变量,意味着该变量的值在初始化后不能被改变。 finalize 允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。 finally 是一个关键字,与 try 和 catch 一起用于异常的处理。finally 块一定会被执行,无论在 try 块中是否有发生异常。 4. String、StringBuffer 与 StringBuilder 的区别 # 可变和适用范围。String 对象是不可变的,而 StringBuffer 和 StringBuilder 是可变字符序列。每次对 String 的操作相当于生成一个新的 String 对象,而对 StringBuffer 和 StringBuilder 的操作是对对象本身的操作,而不会生成新的对象,所以对于频繁改变内容的字符串避免使用 String,因为频繁的生成对象将会对系统性能产生影响。 线程安全。String 由于有 final 修饰,是 immutable 的,安全性是简单而纯粹的。StringBuilder 和 StringBuffer 的区别在于 StringBuilder 不保证同步,也就是说如果需要线程安全需要使用 StringBuffer,不需要同步的 StringBuilder 效率更高。 5. ...