0
点赞
收藏
分享

微信扫一扫

java面试题--容器

中间件小哥 2022-03-11 阅读 115

一、容器

1、Java 容器都有哪些?

Java 容器分为 Collection 和 Map 两大类,其下又有很多子类,如下所示:
• Collection

• List接口

o ArrayList
可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。
添加 add()、查询 get()、删除 remove()、修改 set() 、遍历 使用 for 来迭代数组 也可以使用 for-each 、计算大小 size()、
ArrayList 继承了 AbstractList ,并实现了 List 接口

o LinkedList
一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址。通常使用ArrayList,
在列表开头添加元素 addFirst(“i”),addLast();
在列表开头移除元素 removeFirst()、removeLast()、
获取getFirst()、getLast() 、
迭代元素:使用 for 配合 size() 方法来迭代列表中的元素,也可以使用 for-each 来迭代元素。

o Vector
一个动态数组。和 ArrayList 很相似,但是两者是不同的:
Vector 是同步访问的。包含了许多传统的方法,这些方法不属于集合框架。
Vector 主要用在事先不知道数组的大小,或者只是需要一个可以改变大小的数组的情况。
1、使用构造器Vector()默认大小10,
2、构造方法创建指定大小的向量。Vector(int size)
3、构造方法创建指定大小的向量,并且增量用 incr 指定。增量表示向量每次增加的元素数目。
Vector(int size,int incr)
4、构造方法创建一个包含集合 c 元素的向量:Vector(Collection c)

o Stack
栈是Vector的一个子类,它实现了一个标准的后进先出的栈。
堆栈只定义了默认构造函数,用来创建一个空栈。 堆栈除了包括由Vector定义的所有方法,也定义了自己的一些方法。
1 boolean empty() 测试堆栈是否为空。
2 Object peek( )查看堆栈顶部的对象,但不从堆栈中移除它。
3 Object pop( )移除堆栈顶部的对象,并作为此函数的值返回该对象。
4 Object push(Object element)把项压入堆栈顶部。
5 int search(Object element)返回对象在堆栈中的位置,以 1 为基数。

• Set接口

o HashSet
1、HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。
2、不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。 您必须在多线程访问时显式同步对 HashSet 的并发访问。
3、HashSet 中的元素实际上是对象,一些常见的基本类型可以使用它的包装类。
4、添加元素可以使用 add() 、contains() 方法来判断元素是否存在于集合当中、remove() 方法来删除集合中的元素、remove() 方法来删除集合中的元素、删除集合中所有元素可以使用 clear 方法、计算 HashSet 中的元素数量可以使用 size() 方法、用 for-each 来迭代 HashSet 中的元素,不可以使用普通for函数遍历

o LinkedHashSet
1、具有set集合不重复的特点,同时具有可预测的迭代顺序,也就是我们插入的顺序。
2、linkedHashSet是一个非线程安全的集合
3、LinkedHashSet可以得到super一个父类初始化为一个容器为16大小,加载因子为0.75的Map容器
4、LinkedHashSet是一个哈希表和链表的结合,且是一个双向链表
5、看似无序的集合其中却是有序的,字符串按照字典顺序排序输出

o TreeSet
1、对Set集合中的元素进行排序。是不同步i的
2、 判断元素唯一性的方式:根据比较方法的返回值来判断。是0(零)就存入集合,不是0就不存。因为Set集合是不能有重复的元素,无序。
3、比较排序功能的元素只需要实现Comparable 接口。覆盖接口中CompareTo方法。

• Map接口

• HashMap
1、HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
2、根据键的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。
3、HashMap 是无序的,即不会记录插入的顺序
4、HashMap 的 key 与 value 类型可以相同也可以不同,可以是字符串(String)类型的 key 和 value,也可以是整型(Integer)的 key 和字符串(String)类型的 value。
5、HashMap 的 key 与 value 类型可以相同也可以不同,可以是字符串(String)类型的 key 和 value,也可以是整型(Integer)的 key 和字符串(String)类型的 value。
6、添加键值对(key-value)可以使用 put() 方法、使用 get(key) 方法来获取 key 对应的 value、使用 remove(key) 方法来删除 key 对应的键值对(key-value)、删除所有键值对(key-value)可以使用 clear 方法、计算 HashMap 中的元素数量可以使用 size() 方法、使用 for-each 来迭代 HashMap 中的元素、

o LinkedHashMap
1、HashMap是无序的,也就是说,迭代HashMap所得到的元素顺序并不是它们最初放置到HashMap的顺序。HashMap的这一缺点往往会造成诸多不便,因为在有些场景中,我们确需要用到一个可以保持插入顺序的Map。庆幸的是,JDK为我们解决了这个问题,它为HashMap提供了一个子类 —— LinkedHashMap。虽然LinkedHashMap增加了时间和空间上的开销,但是它通过维护一个额外的双向链表保证了迭代顺序。特别地,该迭代顺序可以是插入顺序,也可以是访问顺序。因此,根据链表中元素的顺序可以将LinkedHashMap分为:保持插入顺序的LinkedHashMap 和 保持访问顺序的LinkedHashMap,其中LinkedHashMap的默认实现是按插入顺序排序的。
2、LinkedHashMap采用的hash算法和HashMap相同,但是它重新定义了Entry。LinkedHashMap中的Entry增加了两个指针 before 和 after,它们分别用于维护双向链接列表。特别需要注意的是,next用于维护HashMap各个桶中Entry的连接顺序,before、after用于维护Entry插入的先后顺序的

• TreeMap
1、不允许出现重复的key;可以插入null键,null值;可以对元素进行排序;无序集合(插入和遍历顺序不一致);
2、与HashMap相比,TreeMap是一个能比较元素大小的Map集合,会对传入的key进行了大小排序。其中,可以使用元素的自然顺序,也可以使用集合中自定义的比较器来进行排序;

• ConcurrentHashMap
1、并发优化的HashMap,默认16把写锁(可以设置更多),有效分散了阻塞的概率,而且没有读锁。
2、数据结构为Segment[],Segment里面才是哈希桶数组,每个Segment一把锁。Key先算出它在哪个Segment里,再算出它在哪个哈希桶里。
3、支持ConcurrentMap接口,如putIfAbsent(key,value)与相反的replace(key,value)与以及实现CAS的replace(key, oldValue, newValue)。
4、没有读锁是因为put/remove动作是个原子动作(比如put是一个对数组元素/Entry 指针的赋值操作),读操作不会看到一个更新动作的中间状态。

• Hashtable
1、 是一个Dictionary具体的实现
2、和HashMap类很相似,但是它支持同步
3、和HashMap类很相似,但是它支持同步
4、要指定用作键的对象,以及要链接到该键的值
5、Hashtable定义了四个构造方法。
一是默认构造方法:Hashtable()
二创建指定大小的哈希表:Hashtable(int size)
三创建了一个指定大小的哈希表,并且通过fillRatio指定填充比例。
填充比例必须介于0.0和1.0之间,它决定了哈希表在重新调整大小之前的充满程度:Hashtable(int size,float fillRatio)
四创建了一个以M中元素为初始化元素的哈希表。哈希表的容量被设置为M的两倍。Hashtable(Map m)

2. Collection 和 Collections 有什么区别?

Collection 是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法,所有集合都是它的子类,比如 List、Set 等。
Collections 是一个包装类,包含了很多静态方法,不能被实例化,就像一个工具类,比如提供的排序方法: Collections. sort(list)

3. List、Set、Map 之间的区别是 什么?

List、Set、Map 的区别主要体现在两个方面:元素是否有序、是否允许元素重复。
三者之间的区别,如下表:
在这里插入图片描述

4. HashMap 和 Hashtable 有什么区别?

• 存储:HashMap 允许 key 和 value 为 null,而 Hashtable 不允许
• 线程安全:Hashtable 是线程安全的,而 HashMap 是非线程安全的。
• 推荐使用:在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用 ConcurrentHashMap 替代

5. 如何决定使用 HashMap 还是 TreeMap?

对于在 Map 中插入、删除、定位一个元素这类操作,HashMap 是最好的选择,因为相对而言 HashMap 的插入会更快,但如果你要对一个 key 集合进行有序的遍历,那 TreeMap 是更好的选择

6. 说一下 HashMap 的实现原理?

HashMap 基于 Hash 算法实现的,我们通过 put(key,value)存储,get(key)来获取。当传入 key 时,HashMap 会根据 key. hashCode() 计算出 hash 值,根据 hash 值将 value 保存在 bucket 里。当计算出的 hash 值相同时,我们称之为 hash 冲突,HashMap 的做法是用链表和红黑树存储相同 hash 值的 value。当 hash 冲突的个数比较少时,使用链表否则使用红黑树。

7. 说一下 HashSet 的实现原理?

HashSet 是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值

8. ArrayList 和 LinkedList 的区别是什么?

• 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现
• 随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找
• 增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。
综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。

9. 如何实现数组和 List 之间的转换?

• 数组转 List:使用 Arrays. asList(array) 进行转换。
• List 转数组:使用 List 自带的 toArray() 方法。
代码示例:

// list to array
List<String> list = new ArrayList<String>();
list. add("王磊");
list. add("的博客");
list. toArray();// array to list
String[] array = new String[]{"王磊","的博客"};
Arrays. asList(array);

10. ArrayList 和 Vector 的区别是什么?

• 线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。
• 性能:ArrayList 在性能方面要优于 Vector
• 扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%

11. Array 和 ArrayList 有何区别?

• Array 可以存储基本数据类型和对象,ArrayList 只能存储对象
• Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。
• Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有

12. 在 Queue 中 poll()和 remove()有什么区别?

• 相同点:都是返回第一个元素,并在队列中删除返回的对象。
• 不同点:如果没有元素 poll()会返回 null,而 remove()会直接抛出 NoSuchElementException 异常
代码示例:

Queue<String> queue = new LinkedList<String>();
queue. offer("string"); // add
System. out. println(queue. poll());
System. out. println(queue. remove());
System. out. println(queue. size());

13. 哪些集合类是线程安全的?

Vector、Hashtable、Stack 都是线程安全的,而像 HashMap 则是非线程安全的,不过在 JDK 1.5 之后随着 Java. util. concurrent 并发包的出现,它们也有了自己对应的线程安全类,比如 HashMap 对应的线程安全类就是 ConcurrentHashMap。

14. 迭代器 Iterator 是什么?

Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允许调用者在迭代过程中移除元素

15. Iterator 怎么使用?有什么特点?

Iterator 使用代码如下:

List<String> list = new ArrayList<>();
Iterator<String> it = list. iterator();while(it. hasNext()){
  String obj = it. next();
  System. out. println(obj);
}

Iterator 的特点是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常

16. Iterator 和 ListIterator 有什么区别?

Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List
Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
ListIterator 从 Iterator 接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置

17. 怎么确保一个集合不能被修改?

可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。
示例代码如下:

List<String> list = new ArrayList<>();
list. add("x");
Collection<String> clist = Collections. unmodifiableCollection(list);
clist. add("y"); // 运行时此行报错
System. out. println(list. size());
举报

相关推荐

0 条评论