设为首页 加入收藏

TOP

每周10道Java面试题:集合类(一)
2019-01-02 00:09:05 】 浏览:338
Tags:每周 Java 试题 集合

1. 你了解哪些集合类型?

答案:你应该知道以下几个最重要的类型:

  • ArrayList
  • LinkedList
  • HashMap
  • HashSet

之后,你可能会被问到这样一些问题,比如应该何时使用此种特定类型,它比其他的好在哪里,它是怎么存储数据的以及隐匿在背后的数据结构是什么。最好的方法是尽可能多地了解这些集合类型,因为这类问题几乎是无穷尽的。

2. HashMap 有什么特点?
答案:HashMap 基于Map接口实现,存储键值对时,可以接收 null 为键值。HashMap 是非同步的。

3. HashMap 的工作原理是怎样的?
答案:HashMap 在 Map.Entry 静态内部类实现中存储键值对,使用哈希算法。在 put 和 get 方法中,使用 hashCode() 和 equals() 方法。

  • 调用 put 方法时,使用键值对中的 Key hashCode() 和哈希算法找出存储键值对索引。键值对 Entry 存储在 LinkedList 中,如果存在 Entry,使用 equals() 方法来检查 Key 是否已经存在:如果存在,则覆盖 value;如果不存在,会创建一个新的 Entry 然后保存。
  • 调用 get 方法时,HashMap 使用键值 Key hashCode() 来找到数组中的索引,然后使用 equals() 方法找出正确的 Entry,返回 Entry 中的 Value。

分析:HashMap 中容量、负荷系数和阀值是重要的参数。HashMap 默认的初始容量是32,负荷系数是0.75阀值 = 负荷系数 x 容量。添加 Entry时,如果 Map 的大小 > 阀值,HashMap 会对 Map 的内容重新哈希,使用更大的容量(容量总是2的幂)。关于 JDK 中的 hash 算法实现以及由此引发的哈希碰撞现象(DDos攻击)都可能是面试的延伸问题。

4. 能否使用任何类作为 Map 的 key?

答案:可以使用任何类作为 Map 的 key,然而在使用之前,需要考虑以下几点:

  • 如果类重写了 equals() 方法,也应该重写 hashCode() 方法。
  • 类的所有实例需要遵循与 equals() 和 hashCode() 相关的规则。
  • 如果一个类没有使用 equals(),不应该在 hashCode() 中使用它。
  • 用户自定义 Key 类最佳实践是使之为不可变的,这样 hashCode() 值可以被缓存起来,拥有更好的性能。不可变的类也可以确保 hashCode() 和 equals() 在未来不会改变,这样就会解决与可变相关的问题了。

分析:如果有一个类 MyKey,在 HashMap 中使用它:

HashMap<MyKey, String> myHashMap = new HashMap<MyKey, String>();

//传递给 MyKey 的 name 参数被用于 equals() 和 hashCode() 中
MyKey key = new MyKey("Pankaj"); // 假设 hashCode=1234
myHashMap.put(key, "Value");

// 以下的代码会改变 key 的 hashCode() 和 equals() 值
key.setName("Amit"); // 假设新的 hashCode=7890

//下面会返回 null,因为 HashMap 会尝试查找存储同样索引的 key,而 key 已被改变了,匹配失败,返回 null
System.out.println(myHashMap.get(new MyKey("Pankaj")));

这就是为什么 String 通常会用作 HashMap 的 Key,因为 String 的设计是不可变的(immutable)。

5. 插入数据时,ArrayList、LinkedList、Vector谁速度较快?
答案:ArrayList、LinkedList、Vector 底层的实现都是使用数组方式存储数据。数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢。

  • Vector 中的方法由于加了 synchronized 修饰,因此 Vector 是线程安全容器,但性能上较ArrayList差
  • LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但插入数据时只需要记录当前项的前后项即可,所以 LinkedList 插入速度较快

6. 多线程场景下如何使用 ArrayList?
答案:
ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的 synchronizedList 方法将其转换成线程安全的容器后再使用。例如像下面这样:

List<String> synchronizedList = Collections.synchronizedList(list);
synchronizedList.add("aaa");
synchronizedList.add("bbb");
for (int i = 0; i < synchronizedList.size(); i++)
{
    System.out.println(synchronizedList.get(i));
}

7. 说一下 ArrayList 的优缺点
答案:ArrayList的优点如下:

  1. ArrayList 底层以数组实现,是一种随机访问模式。ArrayList 实现了 RandomAccess 接口,因此查找的时候非常快。
  2. ArrayList 在顺序添加一个元素的时候非常方便。

ArrayList 的缺点如下:

  1. 删除元素的时候,需要做一次元素复制操作。如果要复制的元素很多,那么就会比较耗费性能。
  2. 插入元素的时候,也需要做一次元素复制操作,缺点同上。

ArrayList 比较适合顺序添加、随机访问的场景。

8. 为什么 ArrayList 的 elementData 加上 transient 修饰?
答案:ArrayList 中的数组定义如下:

private transient Object[] elementData;

再看一下 ArrayList 的定义:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

可以看到 ArrayList 实现了 Serializable 接口,这意味着 ArrayList 支持序列化。transient 的作用是说不希望 elementData 数组被序列化,重写了 writeObject 实现:

private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{
	// Write out element count, and any hidden stuff
	int expected
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Java HashMap源码分析 下一篇ImportNew一周资讯:2019软件趋势

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目