JDK源码解读

1. StringBuffer和StringBuilder原理

  1. 无非是在底层维护了一个char数组,每次append的时候就往char数组里面放字符而已,在最终sb.toString()的时候,用一个new String()方法把char数组里面的内容都转成String,这样,整个过程中只产生了一个StringBuilder对象与一个String对象,非常节省空间。StringBuilder唯一的性能损耗点在于char数组不够的时候需要进行扩容,扩容需要进行数组拷贝,一定程度上降低了效率。

  2. StringBuffer和StringBuilder用法一模一样,唯一的区别只是StringBuffer是线程安全的,它对所有方法都做了同步,StringBuilder是线程非安全的,所以在不涉及线程安全的场景,比如方法内部,尽量使用StringBuilder,避免同步带来的消耗。

  3. 另外,StringBuffer和StringBuilder还有一个优化点,上面说了,扩容的时候有性能上的损耗,那么如果可以估计到要拼接的字符串的长度的话,尽量利用构造函数指定他们的长度。

2. 集合可遍历原理

  1. 在编译的时候编译器会自动将对for这个关键字的使用转化为对目标的迭代器的使用,这就是foreach循环的原理。进而,我们再得出两个结论:

  2. ArrayList之所以能使用foreach循环遍历,是因为ArrayList所有的List都是Collection的子接口,而Collection是Iterable的子接口,ArrayList的父类AbstractList正确地实现了Iterable接口的iterator方法。之前我自己写的ArrayList用foreach循环直接报空指针异常是因为我自己写的ArrayList并没有实现Iterable接口

  3. 任何一个集合,无论是JDK提供的还是自己写的,只要想使用foreach循环遍历,就必须正确地实现Iterable接口。

3. 缓存值原理

  1. Byte、Short、Integer、Long、Char这几个装箱类的valueOf()方法是以128位分界线做了缓存的,假如是128以下且-128以上的值是会取缓存里面的引用的。

  2. Float和Double则没有缓存值,因为是浮点型没有固定值。

4. 集合原理

1. ArrayList

  1. 可为null,存入顺序和拿出顺序一致,可存入重复数据,线程不安全。
  2. 底层数据结构为数组,默认初始化大小为10。但是,若是,我们没有传递List大小,则默认不会分配空间。只有当使用add, 进行添加元素的时候, 才会,开辟空间。每次空间不足,则扩容在原有的基础上扩容1.5倍。
  3. 对elementDate使用了transient关键字修饰,这样序列化ArrayList的时候就无法序列化,目的可能是因为List中存在无数据的节点,直接序列化,浪费空间,因此,产生了writeObject这个方法,只序列化List中有数据的节点。
  4. 遍历:使用普通for循环。

2. LinkedList

  1. 可为null,存入顺序和拿出顺序一致,可存入重复数据,线程不安全。
  2. 底层数据结构为双向链表。
  3. 查找原理:当index小于数组大小的一半的时候(size >> 1表示size / 2,使用移位运算提升代码运行效率),向后查找;否则,向前查找。
  4. 遍历:使用foreach循环。

3. CopyOnWriteArrayList

  1. 可为null,存入顺序和拿出顺序一致,可存入重复数据,线程安全。
  2. 底层为一个Object[]数组。
  3. 原理:就是对于add. remove等等修改操作,都会复制一份数据出来,这样就不会发生错误,但是,因为都去复制数据,导致资源使用过高。源码中使用volatile进行强制刷新每个线程中的数据备份。保证了操作的数据正确性。
  4. 思想:读写分离,最终一致性。
  5. 用法:CopyOnWriteArrayList适用于读操作远多于修改操作的并发场景中。

4. HashMap

  1. key和value可为null,存入顺序和拿出顺序可能不一致,可存入重复数据,线程不安全。
  2. 底层是哈希表。里面存入的节点则是单向链表。
  3. 原理:默认初始化的时候,有16个空间。所有对于需要大量并且快速的对比的话如果都用equal()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equal(),如果equal()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!
  4. 持久化:使用了transient 修饰数据区。因为在不同的虚拟机上,得到的hashCode是不一样的,HashCode和底层实现相关,不同的虚拟机可能有不同的HashCode算法。所以,持久化hashMap无用,但是,java使用writeObject方法,重新持久化了数据,保证了在不同的平台上,依然是可用的。

5. LinkedHashMap

  1. key和value可为null,存入顺序和拿出顺序一致,可存入重复数据,线程不安全。
  2. 底层数据结构为双向链表。
  3. LRU:在new LinkedHashMap(): 可以传入一个boolean参数,false按照插入顺序排序,而true则按照访问方式排序,先访问的,访问完毕之后,放到list最后。

6. TreeMap

  1. key不能为null,value可为null,根据key的自然顺序,或者是重写comparator接口,可存入重复数据,线程不安全。
  2. 底层结构是红黑树。
    1. 红黑树特性:
      1. 根节点与叶节点都是黑色节点,其中叶节点为Null节点
      2. 每个红色节点的两个子节点都是黑色节点,换句话说就是不能有连续两个红色节点
      3. 从根节点到所有叶子节点上的黑色节点数量是相同的
    2. 长度:
      1. 黑树中最短的可能路径是全部为黑色节点的路径
      2. 红黑树中最长的可能路径是红黑相间的路径

猜你喜欢

转载自blog.csdn.net/weixin_38608626/article/details/88592422
今日推荐