常见的集合有哪些?
常见的Java集合可以分为两大类:Collection 和 Map。
- Collection 接口下主要有以下几种实现:
- List:有序的集合,其中的元素可以重复。
- ArrayList:基于动态数组实现,查询速度快,但在中间插入和删除元素时速度较慢。
- LinkedList:基于双向链表实现,插入和删除速度快,但查询速度较慢。
- Vector:与ArrayList类似,但它是线程安全的。
- Set:无序的集合,其中的元素不可以重复。
- HashSet:基于哈希表实现,不保证有序。
- LinkedHashSet:维护元素的插入顺序。
- TreeSet:基于红黑树实现,元素按照自然顺序或者自定义的比较器顺序进行排序。
- Queue:一种先进先出 (FIFO) 的数据结构。
- LinkedList:除了实现List接口外,还实现了Deque接口,可以作为双端队列使用。
- PriorityQueue:基于优先堆实现,元素可以按照自然顺序或者自定义的比较器顺序出队。
- Deque:双端队列,可以在队头和队尾进行元素的插入和删除。
- ArrayDeque:基于动态数组实现的双端队列。
- LinkedList:同样可以作为双端队列使用。
- List:有序的集合,其中的元素可以重复。
- Map:存储键值对,其中键是唯一的。
- HashMap:基于哈希表实现,不保证有序。
- LinkedHashMap:保持键的插入顺序。
- TreeMap:基于红黑树实现,键按照自然顺序或者自定义的比较器顺序进行排序。
- Hashtable:与HashMap类似,但它是线程安全的。
在并发编程中,常用的集合类型有哪些?
Java并发集合主要是java.util.concurrent包中的一些线程安全的集合类,它们能够在多线程环境下提供良好的性能。以下是一些常用的并发集合:
- ConcurrentHashMap:这是一个线程安全的HashMap的变体。与HashTable相比,ConcurrentHashMap在并发环境下提供了更好的性能,因为它只会锁定部分段(segment),而不是整个数据结构。
- CopyOnWriteArrayList 和 CopyOnWriteArraySet:这两个集合类在每次修改(例如添加或删除元素)时都会复制整个底层数组,从而实现线程安全。这使得在迭代期间可以不需要锁定,因此在读多写少的并发环境下表现很好。
- ConcurrentLinkedQueue:一个线程安全的队列,使用链表实现。它采用了一种非阻塞的算法来实现线程安全,因此在高并发环境下性能很好。
- ConcurrentLinkedDeque:一个线程安全的双端队列,同样使用链表实现和非阻塞算法。
- BlockingQueue 接口和它的实现类,如 ArrayBlockingQueue,LinkedBlockingQueue,PriorityBlockingQueue,SynchronousQueue 等:这些队列在尝试获取元素但队列为空,或者尝试添加元素但队列已满时,会导致线程阻塞。这在生产者-消费者模式中非常有用。
- BlockingDeque 接口和它的实现类 LinkedBlockingDeque:这是一个双端版本的BlockingQueue。
- ConcurrentSkipListSet 和 ConcurrentSkipListMap:这两个集合类是线程安全的有序集合。它们内部使用跳表(Skip List)数据结构,可以提供与TreeSet和TreeMap类似的功能,但在并发环境下具有更好的性能。
以上这些并发集合都是设计用来替代传统的线程安全集合(如Vector和HashTable),以及通过Collections.synchronized*方法得到的同步集合。
哪些集合类支持对元素的随机访问?
在Java中,"随机访问"意味着我们可以直接通过索引访问集合中的元素,而不需要从开始位置遍历到所需位置。这通常在基于数组的集合中实现,因为数组支持通过索引的方式直接访问元素。
以下集合类支持对元素的随机访问:
-
ArrayList:ArrayList内部使用动态数组来存储元素,因此可以很快地通过索引访问元素。例如,你可以直接使用
list.get(index)
来获取指定索引位置的元素。 -
Vector:Vector和ArrayList类似,内部也是基于数组实现的。Vector是线程安全的,所以在多线程环境下,如果需要随机访问元素,Vector是一个好的选择。
-
CopyOnWriteArrayList:这是一个线程安全的ArrayList的变体,它也支持通过索引随机访问元素。
需要注意的是,其他一些集合类,如LinkedList、HashSet、TreeSet等,虽然提供了get
或contains
等方法,但是它们不支持通过索引直接访问元素,而是通过遍历或其他方式来查找元素,因此它们不支持随机访问。
例如,LinkedList虽然也有get(index)
方法,但是它需要从头(或尾)开始遍历到指定索引的位置,所以它不被认为是支持随机访问的。
Comparable接口和Comparator接口的主要区别是什么?
Comparable 和 Comparator 都是Java中的接口,它们都用于定义对象的排序方式,但是它们的使用场景和方法有所不同。
-
Comparable接口:如果一个类实现了Comparable接口,那么它的对象就具有可比性,可以进行排序。Comparable接口中只有一个方法,即
compareTo(T o)
,用于比较当前对象与参数对象的大小。实现Comparable接口的类需要覆盖compareTo(T o)
方法,定义对象的自然排序规则。例如,Java的String类和Integer类都实现了Comparable接口,定义了自然的字典序和数值大小排序规则。应用场景:当你需要定义一个类的默认排序方式时,可以让这个类实现Comparable接口。
-
Comparator接口:Comparator接口则更加灵活,它可以定义任意两个对象之间的比较规则。Comparator接口中有两个方法,
compare(T o1, T o2)
和equals(Object obj)
。通常我们只需要实现compare(T o1, T o2)
方法,定义两个对象的比较规则。使用Comparator的好处是你可以定义多种排序规则,并在排序时动态选择使用哪种规则。应用场景:当你需要对一些对象进行排序,但是这些对象的类没有实现Comparable接口,或者你需要使用不同于其自然排序规则的排序规则时,可以使用Comparator。
举例:假设我们有一个Person类,包含姓名和年龄两个字段。我们可以让Person类实现Comparable接口,按照姓名的字典序排序。但是在某些情况下,我们可能需要按照年龄排序,这时我们就可以定义一个实现了Comparator接口的类,按照年龄进行排序。
Collection接口和Collections类的主要区别是什么?
Collection 和 Collections 在Java中都是非常重要的,但它们的功能和用途是不同的:
-
Collection:
- 类型:它是一个接口。
- 所在包:java.util
- 描述:Collection是Java集合框架的根接口,它定义了用于操作数据集合的最基本的方法,例如
add()
,remove()
,contains()
,size()
等。 - 子接口:主要的子接口包括
List
,Set
,Queue
等。这些子接口提供了更具体的数据结构的操作。 - 使用:通常,我们不直接使用Collection接口,而是使用它的具体实现类(例如ArrayList, HashSet等)或它的子接口。
-
Collections:
- 类型:它是一个工具类。
- 所在包:java.util
- 描述:Collections类提供了一系列的静态方法,用于对集合对象进行操作,例如排序、反转、同步包装、查找等。
- 主要方法:
sort()
,reverse()
,synchronizedList()
,min()
,max()
,emptyList()
等。 - 使用:这是一个帮助类,不能被实例化。它为我们提供了许多操作集合的常用的静态方法。
Enumeration接口和Iterator接口有哪些不同?
Enumeration 和 Iterator 都是Java中的接口,用于遍历和操作数据集合的元素,但它们之间存在一些差异:
-
Enumeration:
- 版本:Enumeration接口在JDK 1.0中引入,它是早期Java版本的遗留。
- 方法:Enumeration接口中有两个方法:
hasMoreElements()
和nextElement()
。 - 功能:Enumeration接口只能用于遍历集合,不能进行元素的删除操作。
- 安全性:Enumeration接口的方法不是fail-fast的,在使用Enumeration进行遍历时,其他线程可以修改集合,不会抛出ConcurrentModificationException。
-
Iterator:
- 版本:Iterator接口在JDK 1.2中引入,作为Enumeration的替代,更加强大和灵活。
- 方法:Iterator接口中有三个方法:
hasNext()
,next()
和remove()
。 - 功能:除了遍历集合,Iterator接口还可以通过
remove()
方法删除遍历过程中的元素。 - 安全性:Iterator接口的方法是fail-fast的,如果在使用Iterator进行遍历时,其他线程修改了集合,会立即抛出ConcurrentModificationException。