JAVA面试部分重点内容
二、集合类
1.介绍一下容器中的常见接口?
Collection | 最顶层的接口 |
---|---|
Set | 无序,元素不可重复 |
List | 有序,元素可重复 |
Queue | 先进先出的队列 |
Map | 具有映射关系(key-value) |
Iterator | 输出集合元素,一般用于无序集合 |
ListIterator | Iterator子接口,可双向输出集合中的元素 |
Enumeration | 传统输出接口,已被Iterator取代 |
SortedSet | Set的子接口,对集合中的元素排序 |
SortedMap | Map的子接口,对集合中的元素排序 |
Map.Entry | Map内部接口,描述Map中存储的一组键值元素 |
2.介绍一下Collection的常见方法?
int size() | 获取集合的长度 |
---|---|
boolean isEmpty() | 判断集合是否为空 |
boolean contains(Object o) | 判断集合中是否存在某个对象 |
Iterator<>iterator() | 实例化iterator接口,遍历集合 |
Object[] toArray() | 将集合转换为一个Object数组 |
T[] toArray(T[] a) | 将集合转换为一个指定数据类型的数组 |
boolean add(E e) | 向集合中添加元素 |
boolean remove(Object o) | 向集合中删除元素 |
boolean containsAll(Collection c) | 判断集合中是否存在另一个集合的所有元素 |
boolean addAll(Collection c) | 向集合中添加某个集合的所有元素 |
boolean removeAll(Collection c) | 从集合中删除某个集合的所有元素 |
void clear() | 清除集合中的所有元素 |
boolean equals(Collection c) | 判断两个集合是否相等 |
int hashCode() | 返回集合的哈希值 |
3.介绍一下List的扩展方法?
T get(int index) | 通过下标返回集合中对应位置的元素 |
---|---|
T set(int index,T element) | 在集合中的指定位置存入对象 |
int indexof(Object o) | 从前往后查找某个对象在集合中的位置 |
int lastindexof(Object o) | 从后往前查找某个对象在集合中的位置 |
ListIterator<> listIterator() | 实例化ListIterator接口,遍历List集合 |
List<>subList(int fromIndex,int toIndex) | 通过下标截取List集合 |
4.说说List接口的实现类?
ArrayList:基于数组的实现,非线程安全,效率高,所有的方法都没有 synchronized修饰。
Vector:线程安全,效率低,实现线程安全直接通过 synchronized修饰方法来完成。
Stack: Vector的子类,实现了栈的数据结构,(后进先出)。
- push:入栈方法
- peek:取出栈顶元素,将栈顶复制一份取出,取出之后栈内的数据不变
- pop:取出栈顶元素,直接取出栈顶元素,取完之后栈内的数据减一
LinkedList:实现了先进先出的队列,采用链表的形式存储。
5.说说ArrayList和LinkedList的区别?
内存中存储的形式不同, ArrayList采用的数组的方式, LinkedList采用的是链表的形式。数组在内存中存储空间是连续的,读取快,增删慢。因为数组在内存中是连续的,所以取数据可以通过寻址公式很快求出目标元素的内存地址,因为内存是连续的,所以新增或者删除元素,必然需要移动数据,而且数组长度越长,需要移动的元素越多,操作就越慢。
链表在内存中存储空间是不连续的,读取慢,删快。表在内存中是不连续的,没有固定的公式可以使用,要读取只能从第一位开始一直遍历到目标元素,数据规模越大,操作越慢。增删快,因为只需要重新设置目标元素前后两个节点的后置指针即可,与数据规模无关。
6.LinkedList和Stack都有pop方法,有什么区别和相同点?
pop方法都是取出集合中的第一个元素,但是两者的顺序是相反的, Stack是后进先出”,所以pop取出的是最后一个元素, LinkedList是先进先出”,所以pop取出的是第一个元素,LinkedList现了 Deque接口,而 Deque接口是 Queue的子接口, Queue就是队列,底层实现了队列的数据结构。Queue默认给元素进行升序。实际开发中,不能直接实例化 Queue对象,Queue的实现类是 AbstractQueue,它是一个抽象类,不能直接实例化,开发中需要实现它的子类PriorityQueue。
7.说说Set的实现类?
- HashSet:存储一组无序且唯一的数据
- LinkedHashSet:存储一组有序且唯一的数据
- TreeSet:存储一组有序且唯一的数据
LinkedHashSet的有序是指元素的存储顺序和遍历顺序是一致的,TreeSet的有序是指集合内部会自动对所有元素进行升序排列。
8.介绍一下Map的常见方法?
int size() | 获取集合长度 |
---|---|
boolean isEmpty() | 判断集合是否为空 |
boolean containsKey(Object key) | 判断集合中是否存在某个key |
boolean containsValue(object value) | 判断集合中是否存在某个vaue |
V get(Object key) | 取出集合中key对应的vaue |
V put(K key,V value) | 向集合中存入一组 key-value的元素 |
V remove(Object key) | 删除集合中key对应的value |
void putAll(Map map) | 向集合中添加另一个Map |
void clear() | 清除集合中的所有元素 |
Set<>keySet() | 取出集合中所有的key,返回一个Set |
Collection<>value() | 取出集合中所有的value,返回一个Collection |
Set<Map.Entry<K,V>>entrySet() | 将Map以Set的形式输出 |
int hashCode() | 获取集合的散列值 |
boolean equals(Object o) | 比较两个集合是否相等 |
9.HashTable和HashMap的区别?
- Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的实现,所以HashMap比Hashtable性能高一点
- Hashtable不允许使用null作为key和value。如果试图把null值放进Hashtable中,将会引发空指针异常,但HashMap可以使用null作为key或value。
10.说说Collections工具类的方法?
public static sort() | 对集合进行排序 |
---|---|
public static int binarySearch(List list, Object v) | 查找v在list中的位置,集合必须是升序排列 |
public static get(List list, int index) | 返回list中 index位置的值 |
public static void reverse(List list) | 对list进行反序输出 |
public static void swap(List list,int L, int j) | 交换集合中指定位置的两个元素 |
public static void fill(List list,Object obj) | 将集合中所有元素替换成obj |
public static Object min(List list) | 返回集合中的最小值 |
public static Object max(List list) | 返回集合中的最大值 |
public static boolean replaceAll( List list, object old, Object new) | 在list集合中用new替换old |
public static boolean addAll(List list, Object…obj) | 向集合中添加元素 |
11.描述一下Map put的过程?
- 首次扩容:
先判断数组是否为空,若数组为空则进行第一次扩容(resize); - 计算索引
通过hash算法,计算键值对在数组中的索引; - 插入数据
如果当前位置元素为空,则直接插入数据;
如果当前位置元素非空(hash值相同),若key相同,则直接覆盖其 value;
如果当前位置元素非空(hash值相同),若key不同,则将数据链到链表末端;
若链表长度达到8,则将链表转换成红黑树,并将数据插入树中; - 再次扩容
如果数组中元素个数(size)超过 threshold,则再次进行扩容操作;
12.如何得到一个线程安全的Map?
- 使用Collections工具类,将线程不安全的Map包装成线程安全的Map;
- 使用Java.util.concurrent包下的Map,如ConcurrentHashMap;
- 不建议使用Hashtable,虽然Hashtable是线程安全的,但是性能较差。
13.有哪些线程安全的List?
- Vector
Vector是比较古老的AP,虽然保证了线程安全,但是由于效率低般不建议使用。 - Collections. SynchronizedList
SynchronizedList是 Collections的内部类, Collections提供了 synchronizedList方法,可以将一个线程不安全的List包装成线程安全的List,即 SynchronizedList它比 Vector有更好的扩展性和兼容性,但是它所有的方法都带有同步锁,也不是性能最优的List。 - CopyOnWriteArrayList
CopyonWriteArrayList是ava1.5在 java.util. concurrent包下增加的类,它采用复制底层数组的方式来实现写操作。当线程对此类集合执行读取操作时,线程将会直接读取集合本身,无须加锁与阻塞。当线程对此类集合执行写入操作时,集合会在底层复制-份新的数组,接下来对新的数组执行写入操作。由于对集合的写入操作都是对数组的副本执行操作,因此它是线程安全的。在所有线程安全的List中,它是性能最优的方案。
14.说一说TreeSet和HashSet的区别?
HashSet,TreeSet中的元素都是不能重复的,并且它们都是线程不安全的,二者的区别是:
- HashSet中的元素可以是null,但TreeSet中的元素不能是null;
- HashSet不能保证元素的排列顺序,而TreeSet支持自然排序,定制排序两种排序的方式;
- HashSet底层是采用哈希表实现的,而TreeSet底层是采用红黑树实现的;