文章目录
- 1. Java集合框架有哪些常见的接口?
- 2. ArrayList和LinkedList的区别?
- 3. HashSet和TreeSet的区别?
- 4. 如何选择合适的集合类型?
- 5. 如何对List进行排序?
- 6. 如何去除List中的重复元素?
- 7. 如何实现线程安全的集合?
- 8. 什么是HashMap的工作原理?
- 9. 什么是fail-fast机制?
- 10. 什么是fail-safe机制?
- 11. 如何合并两个List?
- 12. 如何使用Comparator自定义排序?
- 13. 如何实现深拷贝一个集合?
- 14. 什么是Java中的WeakHashMap?
- 15. 什么是EnumSet和EnumMap?
- 16. 如何转换数组为集合?
- 17. 如何实现不可变集合?
- 18. 如何使用PriorityQueue?
- 19. 什么是BlockingQueue?
- 20. 如何使用ConcurrentHashMap?
1. Java集合框架有哪些常见的接口?
Java集合框架主要接口包括:
- Collection:根接口,包含操作单一元素集合的方法(如add、remove、clear等)。
- List:有序集合,允许重复元素。常见实现类有ArrayList、LinkedList、Vector等。
- Set:无序集合,不允许重复元素。常见实现类有HashSet、LinkedHashSet、TreeSet等。
- Queue:队列接口,通常用于FIFO顺序的集合。常见实现类有LinkedList、PriorityQueue等。
- Deque:双端队列接口,允许在两端插入和删除元素。常见实现类有ArrayDeque、LinkedList等。
- Map:键值对集合,不属于Collection接口。常见实现类有HashMap、TreeMap、LinkedHashMap等。
示例代码:
List<String> arrayList = new ArrayList<>();
Set<String> hashSet = new HashSet<>();
Queue<String> linkedListQueue = new LinkedList<>();
Map<String, String> hashMap = new HashMap<>();
2. ArrayList和LinkedList的区别?
-
ArrayList:
- 基于动态数组实现,底层是一个数组。
- 随机访问效率高,时间复杂度为O(1)。
- 插入和删除元素时效率低,尤其是中间位置,时间复杂度为O(n)。
-
LinkedList:
- 基于双向链表实现。
- 随机访问效率低,时间复杂度为O(n)。
- 插入和删除元素时效率高,时间复杂度为O(1),特别是首尾位置。
示例代码:
List<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
System.out.println("ArrayList: " + arrayList);
List<Integer> linkedList = new LinkedList<>();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
System.out.println("LinkedList: " + linkedList);
3. HashSet和TreeSet的区别?
-
HashSet:
- 基于哈希表实现。
- 插入、删除和查找时间复杂度为O(1)。
- 不保证元素的顺序。
-
TreeSet:
- 基于红黑树实现。
- 插入、删除和查找时间复杂度为O(log n)。
- 保证元素的自然顺序(或根据提供的比较器)。
示例代码:
Set<String> hashSet = new HashSet<>();
hashSet.add("b");
hashSet.add("a");
hashSet.add("c");
System.out.println("HashSet: " + hashSet);
Set<String> treeSet = new TreeSet<>();
treeSet.add("b");
treeSet.add("a");
treeSet.add("c");
System.out.println("TreeSet: " + treeSet);
4. 如何选择合适的集合类型?
- List:需要有序集合且允许重复元素时,选择ArrayList或LinkedList。ArrayList适合频繁随机访问,LinkedList适合频繁插入和删除。
- Set:需要无序集合且不允许重复元素时,选择HashSet或TreeSet。HashSet性能更好,TreeSet可以保证有序。
- Queue:需要先进先出(FIFO)集合时,选择LinkedList或PriorityQueue。PriorityQueue适合需要优先级处理的队列。
- Map:需要键值对存储时,选择HashMap或TreeMap。HashMap性能更好,TreeMap可以保证键的有序。
5. 如何对List进行排序?
使用Collections.sort()
方法或者List自带的sort()
方法,可以传入自定义比较器。
示例代码:
List<Integer> list = new ArrayList<>(Arrays.asList(3, 1, 2));
Collections.sort(list); // 自然顺序排序
System.out.println("Sorted List: " + list);
list.sort(Comparator.reverseOrder()); // 逆序排序
System.out.println("Reverse Sorted List: " + list);
6. 如何去除List中的重复元素?
使用HashSet
来过滤重复元素,再转换回List。
示例代码:
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "a"));
Set<String> set = new HashSet<>(list);
list = new ArrayList<>(set);
System.out.println("List after removing duplicates: " + list);
7. 如何实现线程安全的集合?
使用Collections.synchronizedList()
等方法创建线程安全集合,或者使用并发集合类如CopyOnWriteArrayList
、ConcurrentHashMap
。
示例代码:
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
Map<String, String> concurrentMap = new ConcurrentHashMap<>();
// 使用同步集合时需在外部同步
synchronized (synchronizedList) {
synchronizedList.add("a");
}
8. 什么是HashMap的工作原理?
HashMap
基于哈希表实现,通过计算键的哈希码确定存储位置,使用链表或红黑树处理哈希冲突。
- 哈希函数:计算键的哈希码,哈希码经过扰动函数(高位混合)得到哈希值。
- 桶数组:哈希值对桶数组长度取模得到桶的索引,将键值对存储在相应桶中。
- 链表/红黑树:处理哈希冲突,链表长度超过阈值(默认8)时转换为红黑树。
9. 什么是fail-fast机制?
在迭代集合时,如果集合结构被修改(如增加或删除元素),会抛出ConcurrentModificationException
。这种机制用于快速检测并发修改问题。
示例代码:
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
for (String s : list) {
if ("b".equals(s)) {
list.remove(s); // 会抛出ConcurrentModificationException
}
}
10. 什么是fail-safe机制?
并发集合类(如CopyOnWriteArrayList
)在迭代过程中允许修改,使用副本进行迭代,不会抛出ConcurrentModificationException
。
示例代码:
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(Arrays.asList("a", "b", "c"));
for (String s : list) {
if ("b".equals(s)) {
list.remove(s); // 不会抛出异常
}
}
System.out.println("List after modification: " + list);
11. 如何合并两个List?
使用addAll()
方法将一个List中的所有元素添加到另一个List中。
示例代码:
List<String> list1 = new ArrayList<>(Arrays.asList("a", "b"));
List<String> list2 = new ArrayList<>(Arrays.asList("c", "d"));
list1.addAll(list2);
System.out.println("Merged List: " + list1);
12. 如何使用Comparator自定义排序?
创建Comparator
接口的实现类,重写compare
方法,传入Collections.sort()
或List的sort()
方法。
示例代码:
List<String> list = new ArrayList<>(Arrays.asList("apple", "banana", "cherry"));
list.sort(new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length(); // 按字符串长度排序
}
});
System.out.println("List sorted by length: " + list);
13. 如何实现深拷贝一个集合?
使用序列化和反序列化实现深拷贝,或者手动遍历集合并复制每个元素。
示例代码(序列化实现深拷贝):
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class DeepCopy {
public static <T> List<T> deepCopy(List<T> list) throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(list);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (List<T>) ois.readObject();
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
List<String> originalList = new ArrayList<>(Arrays.asList("a", "b", "c"));
List<String> copiedList = deepCopy(originalList);
copiedList.add("d");
System.out.println("Original List: " + originalList);
System.out.println("Copied List: " + copiedList);
}
}
14. 什么是Java中的WeakHashMap?
WeakHashMap
是一种特殊的Map,其键是弱引用,如果键没有其他强引用存在,会被垃圾收集器回收。
示例代码:
import java.util.Map;
import java.util.WeakHashMap;
public class WeakHashMapExample {
public static void main(String[] args) {
Map<String, String> map = new WeakHashMap<>();
String key = new String("key");
map.put(key, "value");
key = null; // key对象没有强引用,会被GC回收
System.gc();
System.out.println("Map after GC: " + map);
}
}
15. 什么是EnumSet和EnumMap?
-
EnumSet:专为枚举类型设计的高效集合,只能包含枚举类型的值,内部使用位向量实现,非常高效。
-
EnumMap:专为枚举类型键设计的高效Map,只能使用枚举类型作为键,内部使用数组实现,性能优于普通的HashMap。
示例代码:
enum Day { MONDAY, TUESDAY, WEDNESDAY }
public class EnumSetAndEnumMap {
public static void main(String[] args) {
EnumSet<Day> enumSet = EnumSet.of(Day.MONDAY, Day.TUESDAY);
System.out.println("EnumSet: " + enumSet);
EnumMap<Day, String> enumMap = new EnumMap<>(Day.class);
enumMap.put(Day.WEDNESDAY, "Midweek");
System.out.println("EnumMap: " + enumMap);
}
}
16. 如何转换数组为集合?
使用Arrays.asList()
方法将数组转换为List,或者使用Collections.addAll()
将数组元素添加到集合中。
示例代码:
String[] array = {"a", "b", "c"};
List<String> list = Arrays.asList(array);
System.out.println("List from array: " + list);
List<String> list2 = new ArrayList<>();
Collections.addAll(list2, array);
System.out.println("List from array using Collections.addAll: " + list2);
17. 如何实现不可变集合?
使用Collections.unmodifiableList()
等方法创建不可变集合,或者使用Guava库的ImmutableList
等类。
示例代码:
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
List<String> immutableList = Collections.unmodifiableList(list);
System.out.println("Immutable List: " + immutableList);
// 尝试修改将抛出UnsupportedOperationException
// immutableList.add("d");
List<String> guavaImmutableList = ImmutableList.of("a", "b", "c");
System.out.println("Guava Immutable List: " + guavaImmutableList);
18. 如何使用PriorityQueue?
PriorityQueue
是基于优先级堆的队列,元素按优先级排序。
示例代码:
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
priorityQueue.add(3);
priorityQueue.add(1);
priorityQueue.add(2);
System.out.println("Priority Queue elements in order:");
while (!priorityQueue.isEmpty()) {
System.out.println(priorityQueue.poll()); // 输出1, 2, 3
}
19. 什么是BlockingQueue?
BlockingQueue
是并发队列,支持线程安全的阻塞插入和移除操作,如ArrayBlockingQueue
、LinkedBlockingQueue
。
示例代码:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class BlockingQueueExample {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();
blockingQueue.put("a");
System.out.println("Element from BlockingQueue: " + blockingQueue.take());
}
}
20. 如何使用ConcurrentHashMap?
ConcurrentHashMap
是线程安全的Map,适用于高并发环境,提供高效的并发操作。
示例代码:
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
Map<String, String> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("key1", "value1");
concurrentMap.put("key2", "value2");
System.out.println("ConcurrentHashMap: " + concurrentMap);
}
}