先来看看集合的继承关系图,以下图所示:java
其中:git
为了方便理解,我隐藏了一些与本文内容无关的信息,隐藏的这些内容会在后面的章节中进行详细地介绍。面试
从图中能够看出,集合的根节点是 Collection,而 Collection 下又提供了两大经常使用集合,分别是:算法
下面咱们分别对集合类进行详细地介绍。数组
Vector 是 Java 早期提供的线程安全的有序集合,若是不须要线程安全,不建议使用此集合,毕竟同步是有线程开销的。安全
使用示例代码:数据结构
Vector vector = new Vector(); vector.add("dog"); vector.add("cat"); vector.remove("cat"); System.out.println(vector);
程序执行结果:[dog]
ide
ArrayList 是最多见的非线程安全的有序集合,由于内部是数组存储的,因此随机访问效率很高,但非尾部的插入和删除性能较低,若是在中间插入元素,以后的全部元素都要后移。ArrayList 的使用与 Vector 相似。函数
LinkedList 是使用双向链表数据结构实现的,所以增长和删除效率比较高,而随机访问效率较差。性能
LinkedList 除了包含以上两个类的操做方法以外,还新增了几个操做方法,如 offer() 、peek() 等,具体详情,请参考如下代码:
LinkedList linkedList = new LinkedList(); // 添加元素 linkedList.offer("bird"); linkedList.push("cat"); linkedList.push("dog"); // 获取第一个元素 System.out.println(linkedList.peek()); // 获取第一个元素,并删除此元素 System.out.println(linkedList.poll()); System.out.println(linkedList);
程序的执行结果:
dog dog [cat, bird]
HashSet 是一个没有重复元素的集合。虽然它是 Set 集合的子类,实际却为 HashMap 的实例,相关源码以下:
public HashSet() { map = new HashMap<>(); }
所以 HashSet 是无序集合,没有办法保证元素的顺序性。
HashSet 默认容量为 16,每次扩充 0.75 倍,相关源码以下:
public HashSet(Collection\<? extends E\> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); }
HashSet 的使用与 Vector 相似。
TreeSet 集合实现了自动排序,也就是说 TreeSet 会把你插入数据进行自动排序。
示例代码以下:
TreeSet treeSet = new TreeSet(); treeSet.add("dog"); treeSet.add("camel"); treeSet.add("cat"); treeSet.add("ant"); System.out.println(treeSet);
程序执行结果:[ant, camel, cat, dog]
能够看出,TreeSet 的使用与 Vector 相似,只是实现了自动排序。
LinkedHashSet 是按照元素的 hashCode 值来决定元素的存储位置,但同时又使用链表来维护元素的次序,这样使得它看起来像是按照插入顺序保存的。
LinkedHashSet 的使用与 Vector 相似。
集合和数组的转换可以使用 toArray() 和 Arrays.asList() 来实现,请参考如下代码示例:
List<String> list = new ArrayList(); list.add("cat"); list.add("dog"); // 集合转数组 String[] arr = list.toArray(new String[list.size()]); // 数组转集合 List<String> list2 = Arrays.asList(arr);
集合与数组的区别,能够参考「数组和排序算法的应用 + 面试题」的内容。
在 Java 语言中排序提供了两种方式:Comparable 和 Comparator,它们的区别也是常见的面试题之一。下面咱们完全地来了解一下 Comparable 和 Comparator 的使用与区别。
Comparable 位于 java.lang 包下,是一个排序接口,也就是说若是一个类实现了 Comparable 接口,就意味着该类有了排序功能。
Comparable 接口只包含了一个函数,定义以下:
package java.lang; import java.util.*; public interface Comparable { public int compareTo(T o); }
Comparable 使用示例,请参考如下代码:
class ComparableTest { public static void main(String[] args) { Dog[] dogs = new Dog[]{ new Dog("老旺财", 10), new Dog("小旺财", 3), new Dog("二旺财", 5), }; // Comparable 排序 Arrays.sort(dogs); for (Dog d : dogs) { System.out.println(d.getName() + ":" + d.getAge()); } } } class Dog implements Comparable\<Dog\> { private String name; private int age; @Override public int compareTo(Dog o) { return age - o.age; } public Dog(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
程序执行结果:
小旺财:3 二旺财:5 老旺财:10
若是 Dog 类未实现 Comparable 执行代码会报程序异常的信息,错误信息为:
Exception in thread "main" java.lang.ClassCastException: xxx cannot be cast to java.lang.ComparablecompareTo() 返回值有三种:
Comparator 是一个外部比较器,位于 java.util 包下,之因此说 Comparator 是一个外部比较器,是由于它无需在比较类中实现 Comparator 接口,而是要新建立一个比较器类来进行比较和排序。
Comparator 接口包含的主要方法为 compare(),定义以下:
public interface Comparator\<T\> { int compare(T o1, T o2); }
Comparator 使用示例,请参考如下代码:
class ComparatorTest { public static void main(String[] args) { Dog[] dogs = new Dog[]{ new Dog("老旺财", 10), new Dog("小旺财", 3), new Dog("二旺财", 5), }; // Comparator 排序 Arrays.sort(dogs,new DogComparator()); for (Dog d : dogs) { System.out.println(d.getName() + ":" + d.getAge()); } } } class DogComparator implements Comparator\<Dog\> { @Override public int compare(Dog o1, Dog o2) { return o1.getAge() - o2.getAge(); } } class Dog { private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
程序执行结果:
小旺财:3 二旺财:5 老旺财:10
答:区别分为如下几个方面:
答:TreeSet 集合实现了元素的自动排序,也就是说无需任何操做,便可实现元素的自动排序功能。
答:Vector 和 ArrayList 的默认容量都为 10,源码以下。
Vector 默认容量源码:
public Vector() { this(10); }
ArrayList 默认容量源码:
private static final int DEFAULT_CAPACITY = 10;
Vector 容量扩充默认增长 1 倍,源码以下:
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); }
其中 capacityIncrement 为初始化 Vector 指定的,默认状况为 0。
ArrayList 容量扩充默认增长大概 0.5 倍(oldCapacity + (oldCapacity >> 1)),源码以下(JDK 8):
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
答:这三者都是 List 的子类,所以功能比较类似,好比增长和删除操做、查找元素等,但在性能、线程安全等方面表现却又不相同,差别以下:
答:Vector 和 ArrayList 的内部结构是以数组形式存储的,所以很是适合随机访问,但非尾部的删除或新增性能较差,好比咱们在中间插入一个元素,就须要把后续的全部元素都进行移动。
LinkedList 插入和删除元素效率比较高,但随机访问性能会比以上两个动态数组慢。
答:Collection 和 Collections 的区别以下:
A:List
B:Set
C:Map
D:HashSet
答:C
答:LinkedHashSet 底层数据结构由哈希表和链表组成,链表保证了元素的有序即存储和取出一致,哈希表保证了元素的惟一性。
答:HashSet 的底层其实就是 HashMap,只不过 HashSet 实现了 Set 接口而且把数据做为 K 值,而 V 值一直使用一个相同的虚值来保存,咱们能够看到源码:
public boolean add(E e) { return map.put(e, PRESENT)==null;// 调用 HashMap 的 put 方法,PRESENT 是一个至始至终都相同的虚值 }
因为 HashMap 的 K 值自己就不容许重复,而且在 HashMap 中若是 K/V 相同时,会用新的 V 覆盖掉旧的 V,而后返回旧的 V,那么在 HashSet 中执行这一句话始终会返回一个 false,致使插入失败,这样就保证了数据的不可重复性。
Integer num = 10; Integer num2 = 5; System.out.println(num.compareTo(num2));
答:程序输出的结果是 1
,由于 Integer 默认实现了 compareTo 方法,定义了天然排序规则,因此当 num 比 num2 大时会返回 1,Integer 相关源码以下:
public int compareTo(Integer anotherInteger) { return compare(this.value, anotherInteger.value); } public static int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); }
答:可使用集合中的 Stack 实现,Stack 是标准的后进先出的栈结构,使用 Stack 中的 pop() 方法返回栈顶元素并删除该元素,示例代码以下。
Stack stack = new Stack(); stack.push("a"); stack.push("b"); stack.push("c"); for (int i = 0; i < 3; i++) { // 移除并返回栈顶元素 System.out.print(stack.pop() + " "); }
程序执行结果:c b a
答:peek() 方法返回第一个元素,但不删除当前元素,当元素不存在时返回 null;poll() 方法返回第一个元素并删除此元素,当元素不存在时返回 null。
答:Comparable 和 Comparator 的主要区别以下:
本文介绍的集合都实现自 Collection,所以它们都有一样的操做方法,如 add()、addAll()、remove() 等,Collection 接口的方法列表以下图:
固然部分集合也在原有方法上扩充了本身特有的方法,如 LinkedList 的 offer()、push() 等方法。本文也提供了数组和集合互转方法,List.toArray() 把集合转换为数组,Arrays.asList(array) 把数组转换为集合。最后介绍了 Comparable 和 Comparator 的使用和区别,Comparable 和 Comparator 是 Java 语言排序提供的两种排序方式,Comparable 位于 java.lang 包下,若是一个类实现了 Comparable 接口,就意味着该类有了排序功能;而 Comparator 位于 java.util 包下,是一个外部比较器,它无需在比较类中实现 Comparator 接口,而是要新建立一个比较器类来进行比较和排序。
_
欢迎关注个人公众号,回复关键字“Java” ,将会有大礼相送!!! 祝各位面试成功!!!