32道常见的Java基础面试题 (4)

当与具体实现打交道的时候,克隆或序列化的语义和含义才发挥作用。所以,具体实现应该决定如何对它进行克隆或序列化,或它是否可以被克隆或序列化。在所有的实现中授权克隆和序列化,最终导致更少的灵活性和更多的限制,特定的实现应该决定它是否可以被克隆和序列化。

21. 为何 Map 接口不继承 Collection 接口?

尽管 Map 接口和它的实现也是集合框架的一部分,但 Map 不是集合,集合也不是 Map。因此,Map 继承 Collection 毫无意义,反之亦然。

如果 Map 继承 Collection 接口,那么元素去哪儿?Map 包含key-value 对,它提供抽取 key 或 value 列表集合的方法,但是它不适合“一组对象”规范。

22. 什么是迭代器(Iterator)?

Iterator 接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素,但是不可以直接调用集合的 remove(Object Obj) 删除,可以通过迭代器的 remove() 方法删除。

23. Iterator 和 ListIterator 的区别是什么?

Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。 

Iterator 对集合只能是前向遍历,ListIterator 既可以前向也可以后向。 

ListIterator 实现了 Iterator 接口,并包含其他的功能。比如:增加元素,替换元素,获取前一个和后一个元素的索引等等。

24. Java 中的 HashMap 的工作原理是什么?

我们知道在 Java 中最常用的两种结构是数组和模拟指针(引用),几乎所有的数据结构都可以利用这两种来组合实现,HashMap 也是如此。实际上 HashMap 是一个“链表散列”。

HashMap 是基于 hashing 的原理,我们使用 put(key, value) 存储对象到 HashMap 中,使用 get(key) 从 HashMap 中获取对象。当我们给 put() 方法传递键和值时,我们先对键调用 hashCode() 方法,返回的 hashCode 用于找到 bucket 位置来储存 Entry 对象。

25. 当两个对象的 hashcode 相同会发生什么?

因为 hashcode 相同,所以它们的 bucket 位置相同,“碰撞”会发生。因为 HashMap 使用链表存储对象,这个 Entry(包含有键值对的 Map.Entry 对象)会存储在链表中。

26. 如果两个键的 hashcode 相同,你如何获取值对象?

当我们调用 get() 方法,HashMap 会使用键对象的 hashcode 找到 bucket 位置,然后会调用 keys.equals() 方法去找到链表中正确的节点,最终找到要找的值对象。

27. hashCode() 和 equals() 方法有何重要性?

HashMap 使用 Key 对象的 hashCode() 和 equals() 方法去决定 key-value 对的索引。当我们试着从 HashMap 中获取值的时候,这些方法也会被用到。

如果这些方法没有被正确地实现,在这种情况下,两个不同 Key 也许会产生相同的 hashCode() 和 equals() 输出,HashMap 将会认为它们是相同的,然后覆盖它们,而非把它们存储到不同的地方。

同样的,所有不允许存储重复数据的集合类都使用 hashCode() 和 equals() 去查找重复,所以正确实现它们非常重要。equals() 和 hashCode() 的实现应该遵循以下规则: 

如果 o1.equals(o2),那么o1.hashCode() == o2.hashCode()总是为true的。 
如果 o1.hashCode() == o2.hashCode(),并不意味着o1.equals(o2)会为true。 

28. HashMap 和 HashTable 有什么区别?

1. HashMap 是非线程安全的,HashTable 是线程安全的。 

2. HashMap 的键和值都允许有 null 值存在,而 HashTable 则不行。 

3. 因为线程安全的问题,HashMap 效率比 HashTable 的要高。 

4. HashTable 是同步的,而 HashMap 不是。因此,HashMap 更适合于单线程环境,而 HashTable 适合于多线程环境。 

一般现在不建议用 HashTable,一是 HashTable 是遗留类,内部实现很多没优化和冗余。二是即使在多线程环境下,现在也有同步的 ConcurrentHashMap 替代,没有必要因为是多线程而用 HashTable。

 29. 如何决定选用 HashMap 还是 TreeMap?

对于在 Map 中插入、删除和定位元素这类操作,HashMap 是最好的选择。然而,假如你需要对一个有序的 key 集合进行遍历, TreeMap 是更好的选择。基于你的 collection 的大小,也许向 HashMap 中添加元素会更快,将 map 换为 TreeMap 进行有序 key 的遍历。

30. ArrayList 和 Vector 有何异同点?

ArrayList 和 Vector 在很多时候都很类似。 

(1)两者都是基于索引的,内部由一个数组支持。 

(2)两者维护插入的顺序,我们可以根据插入顺序来获取元素。 

(3)ArrayList 和 Vector 的迭代器实现都是 fail-fast 的。 

(4)ArrayList 和 Vector 两者允许 null 值,也可以使用索引值对元素进行随机访问。  

以下是ArrayList和Vector的不同点。 

(1)Vector 是同步的,而 ArrayList 不是。然而,如果你寻求在迭代的时候对列表进行改变,你应该使用 CopyOnWriteArrayList。 

(2)ArrayList 比 Vector 快,它因为有同步,不会过载。 

(3)ArrayList 更加通用,因为我们可以使用 Collections 工具类轻易地获取同步列表和只读列表。

 31. Array 和 ArrayList 有何区别?什么时候更适合用 Array?

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyyjss.html