Java基础面试题

ArrayList 和 Vector 的区别。

ArrayList是线程不安全的,Vector是线程安全的。Veator中的方法是同步方法(Synchronized修饰),因此ArrayList执行效率相对较高。

 

说说 ArrayList,Vector, LinkedList 的存储性能和特性。

ArrayList和Vector底层使用数组进行数据存储,查询快,增删慢,区别在于ArrayList是线程不安全的。当需要扩容时,Vector增加一倍,而ArrayList增加原来的一半。

LinkedList底层基于链表进行数据存储,查询慢,但增删快,主要适用增删较多的场景。

快速失败 (fail-fast) 和安全失败 (fail-safe) 的区别是什么?

fail-fast和fail-safe的区别: 

fail-safe允许在遍历的过程中对容器中的数据进行修改,而fail-fast则不允许。

fail-fast ( 快速失败 )

fail-fast:直接在容器上进行遍历,在遍历过程中,一旦发现容器中的数据被修改了,会立刻抛出ConcurrentModificationException异常导致遍历失败。java.util包下的集合类都是快速失败机制的, 常见的的使用fail-fast方式遍历的容器有HashMap和ArrayList等。

在使用迭代器遍历一个集合对象时,比如增强for,如果遍历过程中对集合对象的内容进行了修改(增删改),会抛出ConcurrentModificationException 异常.

fail-fast的出现场景

在我们常见的java集合中就可能出现fail-fast机制,比如ArrayList,HashMap。在多线程和单线程环境下都有可能出现快速失败。

 

fail-safe ( 安全失败 )

fail-safe:这种遍历基于容器的一个克隆。因此,对容器内容的修改不影响遍历。java.util.concurrent包下的容器都是安全失败的,可以在多线程下并发使用,并发修改。常见的的使用fail-safe方式遍历的容器有ConcerrentHashMap和CopyOnWriteArrayList等。

原理:

采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception。

缺点:

基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。

hashmap 的数据结构。

HashMap基于哈希表的Map接口实现,是以key-value存储形式存在,即主要用来存放键值对。HashMap的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。

JDK1.8之前的HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了节解决哈希碰撞(两个对象调用的hashCode方法计算的哈希码值一致导致计算的数组索引值相同)而存在的(“拉链法”解决冲突)。

JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(或者红黑树的边界值,默认为8)并且当前数组的长度大于64时,此时此索引位置上的所有数据改为使用红黑树存储。

数组里面都是key-value的实例,在JDK1.8之前叫做Entry,在JDK1.8之后叫做Node。

HashMap什么时候进行扩容?

当hashmap中的元素个数超过数组大小*loadFactor时,就会进行数组扩容,loadFactor的默认值为0.75,也就是说,默认情况下,数组大小为16,那么当hashmap中元素个数超过16*0.75=12的时候,就把数组的大小扩展为2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知hashmap中元素的个数,那么预设元素的个数能够有效的提高hashmap的性能

List、Map、Set 三个接口,存取元素时,各有什么特点?

List与Set都是单列元素的集合,它们有一个功共同的父接口Collection。

Set里面不允许有重复的元素,

  存元素:add方法有一个boolean的返回值,当集合中没有某个元素,此时add方法可成功加入该元素时,则返回true;当集合含有与某个元素equals相等的元素时,此时add方法无法加入该元素,返回结果为false。

  取元素:没法说取第几个,只能以Iterator接口取得所有的元素,再逐一遍历各个元素。

List表示有先后顺序的集合,

  存元素:多次调用add(Object)方法时,每次加入的对象按先来后到的顺序排序,也可以插队,即调用add(int index,Object)方法,就可以指定当前对象在集合中的存放位置。

  取元素:方法1:Iterator接口取得所有,逐一遍历各个元素

      方法2:调用get(index i)来明确说明取第几个。

Map是双列的集合:

  存放用put方法:put(obj key,obj value),每次存储时,要存储一对key/value,不能存储重复的key,这个重复的规则也是按equals比较相等。

  取元素:用get(Object key)方法根据key获得相应的value。

    也可以获得所有的key的集合,还可以获得所有的value的集合,

    还可以获得key和value组合成的Map.Entry对象的集合。

Set 里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用 == 还是 equals()? 它们有何区别?

==是判断对象的内存地址,s1==s2,s2的引用的对象跟s1是同一个。

Object类的equals 也是判断对象的内存地址。底层也是用的==。

有一些类复写了equals(),判断的是此对象的具体内容  

两个对象值相同 (x.equals(y) == true),但却可有不同的 hash code,这句话对不对?

不对,值相同hashcode一定相同,hashcode相同值不一定相同。

 

heap 和 stack 有什么区别。

 1、heap是堆,stack是栈。

2、stack的空间由操作系统自动分配和释放,heap的空间是手动申请和释放的,heap常用new关键字来分配。

3、stack空间有限,heap的空间是很大的自由区。

Java 集合类框架的基本接口有哪些?

Collection 和Map ,一个元素集合,一个是键值对集合;

其中List和Set接口继承了Collection接口,一个是有序元素集合,一个是无序元素集合;

而ArrayList和 LinkedList 实现了List接口,HashSet实现了Set接口,这几个都比较常用;

HashMap 和HashTable实现了Map接口,并且HashTable是线程安全的,但是HashMap性能更好

 

Java集合类里最基本的接口有:
Collection:单列集合的根接口
List:元素有序  可重复 
ArrayList:类似一个长度可变的数组 。适合查询,不适合增删
LinkedList:底层是双向循环链表。适合增删,不适合查询。
Set:元素无序,不可重复
HashSet:根据对象的哈希值确定元素在集合中的位置
TreeSet: 以二叉树的方式存储元素,实现了对集合中的元素排序
Map:双列集合的根接口,用于存储具有键(key)、值(value)映射关系的元素。
HashMap:用于存储键值映射关系,不能出现重复的键key
TreeMap:用来存储键值映射关系,不能出现重复的键key,所有的键按照二叉树的方式排列

 

HashSet和TreeSet的区别?

Hashset 的底层是由哈希表实现的,Treeset 底层是由红黑树实现的。 如果需要在Treeset 中插入对象,需要实现Comparable 接口,为其指定比较策略。

HashSet 的底层实现是什么?

HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证set 的迭代顺序;特别是它不保证该顺序恒久不变,此类允许使用null元素。 
在HashSet中,元素都存到HashMap键值对的Key上面,而Value时有一个统一的值private static final Object PRESENT = new Object();

(定义一个虚拟的Object对象作为HashMap的value,将此对象定义为static final。)

LinkedHashMap 的实现原理?

1. LinkedHashMap概述:

   LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
   LinkedHashMap实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。
   注意,此实现不是同步的。如果多个线程同时访问链接的哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步。

2. LinkedHashMap的实现:

   对于LinkedHashMap而言,它继承与HashMap、底层使用哈希表与双向链表来保存所有元素。其基本操作与父类HashMap相似,它通过重写父类相关的方法,来实现自己的链接列表特性。

 

LinkedHashMap采用的hash算法和HashMap相同,但是它重新定义了数组中保存的元素Entry,该Entry除了保存当前对象的引用外,

还保存了其上一个元素before和下一个元素after的引用,从而在哈希表的基础上又构成了双向链接列表。

 

 

为什么集合类没有实现 Cloneable 和 Serializable 接口?

集合的接口List中并没有定义继承序列化和克隆接口, 并且其他的集合接口也都没有实现。

克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该由集合类的具体实现来决定如何被克隆或者是序列化。

克隆分为深拷贝和浅拷贝, 具体的拷贝实现需要用户自己根据对象的特性来实现, 集合类又是一个容器, 会装载不同的对象(各种各样的). 不可能每个对象都实现克隆,

序列化也是同样的道理。

虽然List没有继承序列化和克隆接口,但是它的子类ArrayList都继承了这两个接口。 并且根据自己的特性对这两个接口的实现都进行了自己的优化。

什么是迭代器 (Iterator)?

Iterator接口提供了很多对集合元素进行迭代的方法。

每一个集合类都包括了可以返回迭代器实例的迭代方法。

迭代器可以在迭代过程中删除底层集合的元素,但是不可以直接调用集合的remove(Object obj)删除,可以通过迭代器的remove()方法删除

Iterator 和 ListIterator 的区别是什么?

1、遍历

使用Iterator,可以遍历所有集合,如Map,List,Set;但只能在向前方向上遍历集合中的元素。

使用ListIterator,只能遍历List实现的对象,但可以向前和向后遍历集合中的元素。

2、添加元素

Iterator无法向集合中添加元素;而,ListIteror可以向集合添加元素。

3、修改元素

Iterator无法修改集合中的元素;而,ListIterator可以使用set()修改集合中的元素。

4、索引

Iterator无法获取集合中元素的索引;而,使用ListIterator,可以获取集合中元素的索引。

数组 (Array) 和列表 (ArrayList) 有什么区别?什么时候应该使用 Array 而不是 ArrayList?

区别:

Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
Array大小是固定的,ArrayList的大小是动态变化的。
ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。

 

适用:

如果想要保存一些在整个程序运行期间都会存在而且不变的数据,我们可以将它们放进一个全局数组里,

但是如果我们单纯只是想要以数组的形式保存数据,而不对数据进行增加等操作,只是方便我们进行查找的话,那么,我们就选择ArrayList。

而且还有一个地方是必须知道的,就是如果我们需要对元素进行频繁的移动或删除,或者是处理的是超大量的数据,

那么,使用ArrayList就真的不是一个好的选择,因为它的效率很低,使用数组进行这样的动作就很麻烦,那么,我们可以考虑选择LinkedList。

Comparable 和 Comparator 接口是干什么的?列出它们的区别

Comparable & Comparator 都是用来实现集合中元素的比较、排序的,只是 Comparable 是在集合内部定义的方法实现的排序,

Comparator 是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。

 

两种方式,各有各的特点:使用Comparable方式比较时,我们将比较的规则写入了比较的类型中,其特点是高内聚。

但如果哪天这个规则需要修改,那么我们必须修改这个类型的源代码。如果使用Comparator方式比较,那么我们不需要修改比较的类,

其特点是易维护,但需要自定义一个比较器,后续比较规则的修改,仅仅是改这个比较器中的代码即可。

 

简而言之:Comparable 是和类绑定一起,Comparator 只是一个比较器。

Collection 和 Collections 的区别。

collection是集合接口,collections是集合工具类。

 

posted @ 2022-01-06 11:29  佛祖让我来巡山  阅读(73)  评论(0编辑  收藏  举报

佛祖让我来巡山博客站 - 创建于 2018-08-15

开发工程师个人站,内容主要是网站开发方面的技术文章,大部分来自学习或工作,部分来源于网络,希望对大家有所帮助。

Bootstrap中文网