桥下红药

以无心之心读书

Java面试题基础操作

总分类 评论已关闭

1. Java基本数据类型 :

  • int、long、double、float、byte、short、char、boolean
  1. byte:占用1个字节
  2. int:占用4个字节
  3. float:占用4个字节
  4. long:占用8个字节
  5. double:占用8个字节
  6. short:占用2个字节
  7. char:占用2个字节
  8. boolean:单独使用占用4字节,boolean数组里面每个占1个字节

批注:1字节 = 8 位 ,是基础数据单位,如:0x00000000,8位只能表示 -128~127 范围,一共255个数。所以更大范围的数需要多个字节表示。

2. Java集合框架

ArrayList

  • 数据底层是变长的数组,操作数据就是操作数组。
  • 默认长度是10,随着添加数据到最大阈值会扩容数组(copy),每次扩容现有容量的50%。
  • value可以是 Null,非线程安全。
  • 根据下标遍历速度快,根据下标访问速度快
  • 根据内容查找速度慢,插入和删除需要移动后续数据位置,所以效率不高,除非只是添加\删除到尾部

LinkedList

  • 是个利用前后指针的双向链表结构
  • 数据有序,value可以是 Null,非线程安全。
  • 添加数据只需要修改 prev 和 next 指针,所以固定开销,相比ArrayList不需要移动数据,插入效率高,根据值查找数据虽然会分段遍历,但是效率相比ArrayList要低。

备注:内部只有first、last节点和一个计数器变量。

HashMap

  • 数据结果 HashMapEntry<K,V>[] 的数组。Entry是个单向链表 结构如下:
final K key;
V value;
HashMapEntry<K,V> next;
int hash;
  • 默认初始容量:16,必须是 2 的整数次方。
  • 因为位置是根据key hash之后确定的,所以可以很快定位,查找效率还是不错的。
  • key存放在Set里面,所以允许重复。key可以为Null,并总是会存在table第一位
  • 数据是无序的。
  • 非线程安全

LinkedHashMap

  • 类似于 LinkedList 和 HashMap 的集合体,LinkedHashMap 继承 HashMap ,比 HashMap 多出了个 双向链表来维持有序。

  • 数据有序,key\value 都可以为 Null ,对比可以得出结论 带 Linked的一般都是有序的。

  • accessOrder true 为访问顺序,意思就是 get 数据的话这个数据就会被移动到链表尾部,适合读取缓存的策略。

HashTable 基本已经废弃了,和 HashMap 不同点大约就是

  • Key 为 Null 直接抛异常。
  • 多线程下数据是同步操作的。
  • 继承 于一个废弃的 Dictionary 类。
  • ** 推荐使用 ConcurrentHashMap **

ConcurrentHashMap

HashTable同步是锁住了整个 table 表,那么不管是取任何 Key 的数据都会 抢同一个锁,造成不必要的等到,ConcurrentHashMap 把数据分组,然后给每个组加锁,这样大大加快了效率。

  • 区别于 HashMap ,ConcurrentHashMap 扩容的话只会扩容 当前 Segment (数据段)

  • Segments数组的长度最大为 65536

  • HashEntry 里面结构和 HashMap 是一样的,通过 Hash 将数据分段,取值再 通过 Hash 算法定位数据….

ConcurrentHashMap的size操作

如果我们要统计整个ConcurrentHashMap里元素的大小,就必须统计所有Segment里元素的大小后求和。Segment里的全局变量count是一个volatile变量,那么在多线程场景下,我们是不是直接把所有Segment的count相加就可以得到整个ConcurrentHashMap大小了呢?不是的,虽然相加时可以获取每个Segment的count的最新值,但是拿到之后可能累加前使用的count发生了变化,那么统计结果就不准了。所以最安全的做法,是在统计size的时候把所有Segment的put,remove和clean方法全部锁住,但是这种做法显然非常低效。

因为在累加count操作过程中,之前累加过的count发生变化的几率非常小,所以ConcurrentHashMap的做法是先尝试2次通过不锁住Segment的方式来统计各个Segment大小,如果统计的过程中,容器的count发生了变化,则再采用加锁的方式来统计所有Segment的大小。

那么ConcurrentHashMap是如何判断在统计的时候容器是否发生了变化呢?使用modCount变量,在put , remove和clean方法里操作元素前都会将变量modCount进行加1,那么在统计size前后比较modCount是否发生变化,从而得知容器的大小是否发生变化。

注:JDK 1.8 修改了ConcurrentHashMap的实现,将Segment改成了红黑树。

上一篇

评论已关闭。