接口 vs 抽象类的区别?

在面向对象编程中,抽象类和接口是两个经常被用到的语法概念,是面向对象四大特性,以及很多设计模式、设计思想、设计原则编程实现的基础。

比如:我们可以使用接口来实现面向对象的抽象特性、多态特性和基于接口而非实现的设计原则,使用抽象类来实现面向对象的继承特性和模板设计模式等。

Java

Java 集合总结

集合中用到的数据结构有以下几种:

  • 数组: 最常用的数据结构之一。数组的特点是长度固定,可以用下标索引,并且所有的元素的类型都是一致的。使用时尽量把数组封装在一个类里,防止数据被错误的操作弄乱。
  • 链表: 是一种由多个节点组成的数据结构,并且每个节点包含有数据以及指向下一个节点的引用,在双向链表里,还会有一个指向前一个节点的引用。例如,可以用单向链表和双向链表来实现堆栈和队列,因为链表的两端都是可以进行插入和删除的动作的。当然,也会有在链表的中间频繁插入和删除节点的场景。
  • 树: 是一种由节点组成的数据结构,每个节点都包含数据元素,并且有一个或多个子节点,每个子节点指向一个父节点可以表示层级关系或者数据元素的顺序关系。如果树的每个子节点最多有两个叶子节点,那么这种树被称为二叉树。二叉树是一种非常常用的树形结构, 因为它的这种结构使得节点的插入和删除都非常高效。树的边表示从一个节点到另外一个节点的快捷路径。
  • 堆栈: 只允许对最后插入的元素进行操作(也就是后进先出,Last In First Out – LIFO)。如果你移除了栈顶的元素,那么你可以操作倒数第二个元素,依次类推。这种后进先出的方式是通过仅有的peek(),push()和pop()这几个方法的强制性限制达到的。这种结构在很多场景下都非常实用,例如解析像(4+2)*3这样的数学表达式,把源码中的方法和异常按照他们出现的顺序放到堆栈中,检查你的代码看看小括号和花括号是不是匹配的,等等。
  • 队列: 和堆栈有些相似,不同之处在于在队列里第一个插入的元素也是第一个被删除的元素(即是先进先出)。这种先进先出的结构是通过只提供peek(),offer()和poll()这几个方法来访问数据进行限制来达到的。例如,排队等待公交车,银行或者超市里的等待列队等等,都是可以用队列来表示。
Java

LinkedHashMap 底层实现原理分析

LinkedHashMap继承自HashMap实现了Map接口。基本实现同HashMap一样,不同之处在于LinkedHashMap保证了迭代的有序性。其内部维护了一个双向链表,解决了 HashMap不能随时保持遍历顺序和插入顺序一致的问题。除此之外,LinkedHashMap对访问顺序也提供了相关支持。在一些场景下,该特性很有用,比如缓存。

在实现上,LinkedHashMap很多方法直接继承自HashMap,仅为维护双向链表覆写了部分方法。所以,要看懂 LinkedHashMap 的源码,需要先看懂 HashMap 的源码。

默认情况下,LinkedHashMap的迭代顺序是按照插入节点的顺序。也可以通过改变accessOrder参数的值,使得其遍历顺序按照访问顺序输出。

这里我们只讨论LinkedHashMap和HashMap的不同之处,LinkedHashMap的其他操作和特性具体请参考HashMap

我们先来看下两者的区别:

Java

LinkedList 底层实现原理分析

  • 在Java.util包下
  • 继承自AbstractSequentialList
  • 实现 List 接口,能对它进行队列操作。
  • 实现 Deque 接口,即能将LinkedList当作双端队列使用。
  • 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
  • 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
  • 允许包含null值
  • 迭代器可以快速报错
  • 非线程安全的,如果在多线程中使用(修改),需要在外部作同步处理。

LinkedList是一种可以在任何位置进行高效地插入和移除操作的有序序列,它是基于双向链表实现的。内部有三个变量,size表示链表中元素的个数, first指向链表头部,last指向链表尾部。 结构图如下图所示

Java

Vector 底层实现原理分析

Vector,一个可变长的数组,底层实现与 ArrayList 大同小异,但Vector是同步的(线程安全),Vector的很多方法之前都加了关键字synchronized,所以是线程安全的。

由于Vector的实现和ArrayList的实现大同小异,这里就不再逐一分析Vector中的方法,主要分析一下和ArrayList不同的方法。

首先我们还是来看以下Vector中定义的变量

Java

ArrayList动态扩容机制

我们通过一个具体的例子看一下ArrayList的扩容效果
先看一下ArrayList的初始容量

ArrayList<Integer> array = new ArrayList<>();
Integer capacity = getCapacity(array);
int size = array.size();
System.out.println("容量:"+capacity);
System.out.println("大小:"+size);
容量:0
大小:0

getCapacity()方法是用来获取集合容量的,ArrayList通过一个elementData对象数组储存数据,也就是说ArrayList的容量就是该数组的长度。所以我们只要得到了elementData数组就可以知道ArrayList的实际容量。

Java