面试题解析

1、Java容器都有哪些?

  • 数组
  • Collection接口:List、Set、、Queue接口
  • Map接口
  • Iteror迭代器

2、Collection 和 Collections 有什么区别?

Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。
它有两个常用的子接口,
List:对元素都有定义索引。有序的。可以重复元素。
Set:不可以重复元素。无序

Collections是集合框架中的一个工具类。该类中的方法都是静态的
提供的方法中有可以对list集合进行排序,二分查找二分查找等方法。
通常常用的集合都是线程不安全的。因为要提高效率。
如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。

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

List集合,Set集合都是继承Collection父接口。

Map没有继承Collection父接口,Map是键值对集合key到value的映射,是把键对象和值对象进行映射的集合。

  • list是一种有序集合,按照对象进入的顺序保存对象,并且允许重复对象,插入多个null值。

    list查找效率快,但增删效率慢,增删会引起其他元素位置发生改变。

  • set是无序的集合,不是按照对象进入的顺序保存,不可重复,只允许一个null值出现。

    set检索元素效率低,而增删效率快,增删不会引起其他元素位置发生改变。

  • map以键值对的方式存储元素,根据键得到值,所有Map集合的Key是无序不可重复的,key和value都是引用数据类型,存的都是内存的地址。

 4、 HashMap 和 Hashtable 有什么区别?

1、hash值不同

HashTable:直接使用对象的hashCode

HashMap:重新计算hash值

2、两个遍历方式的内部实现不同

Hashtable、HashMap两者都是使用了Iterator,但是,因为一些历史原因,Hashtable除了使用了Iterator之外,还使用了Enumeration。

3、是否提供contains方法

Hashtable:Hashtable和HashMap不同,它保留了contains、containsValue以及containsKey3个方法

HashMap:它去掉了Hashtable的contains方法,改为了containsKey和containsValue

4、内部实现使用的数组初始化和扩容方式不同

HashTable:在不指定容量的情况下的默认容量为11;不要求底层数组的容量一定要为2的整数次幂;扩容时将容量变为原来的2倍加1。在此我向大家推荐一个架构学习交流圈。交流学习指导伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

HashMap:在不指定容量的情况下的默认容量为16;要求一定为2的整数次幂;扩容时,将容量变为原来的2倍

HashTable中hash数组默认大小是11,增加的方式是old*2+1

5、key和value是否允许null值

Hashtable:key和value都不允许出现null值

HashMap:null能够作为键,这样的键只有一个,能够有一个或者是多个键所对应的值为null

6、线程安全性不同

Hashtable:Synchronize;在多线程并发的情况下,能够直接使用Hashtable,不要自己为它的方法实现同步

HashMap:在缺省情况下是非Synchronize的;使用HashMap的时候就需要自己增加同步处理;HashMap是线程不安全的

7、继承的父类不同

Hashtable:继承Dictionary类

HashMap:继承AbstractMap类

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

1.​​TreeMap<K,V>​​​的Key值是要求实现​​java.lang.Comparable​​,所以迭代的时候TreeMap默认是按照Key值升序排序的;TreeMap的实现是基于红黑树结构。适用于按自然顺序或自定义顺序遍历键(key)。

2.​​HashMap<K,V>​​​的Key值实现散列​​hashCode()​​,分布是散列的、均匀的,不支持排序;数据结构主要是桶(数组),链表或红黑树。适用于在Map中插入、删除和定位元素。

你需要得到一个有序的结果时就应该使用TreeMap(因为HashMap中元素的排列顺序是不固定的)。除此之外,由于HashMap有更好的性能,所以大多不需要排序的时候我们会使用HashMap。

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

HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,会根据hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。

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

  • 是基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。
  • 当我们试图把某个类的对象当成 HashMap的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的equals(Object obj)方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。

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

  • .默认情况下,比如调用ArrayList和LinkedList的add(e)方法,都是插入在最后,如果这种操作比较多,那么就用LinkedList,因为不涉及到扩容。
  • 如果调用ArrayList和LinkedList的add(index, e)方法比较多,就要具体考虑了,因为ArrayList可能会扩容,LinkedList需要遍历链表,这两种到底哪种更快,是没有结论的,得具体情况具体分析。
  • 还有,如果是插入场景比较少,但经常需要查询的话,查询分两种,第一种就是普通遍历,也就是经常需要对List中的元素进行遍历,那么这两种是区别不大的,遍历链表和遍历数组的区别,第二种就是经常需要按指定下标获取List中的元素,如果这种情况如果比较多,那么就用ArrayList

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

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

10、 Array 和 ArrayList 有何区别?

  •  数组(Array)是有序的元素序列。若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。这些有序排列的同类数据元素的集合称为数组。
    数组是用于储存多个相同类型数据的集合

11、哪些集合类是线程安全的?

  • vector:就比arraylist多了个同步化机制(线程安全)
  • statck:堆在类,先进后出
  • hashtable:就比hashmap多了个线程安全
  • enumeration:枚举,相当于迭代器

12、迭代器 Iterator 是什么?

(iterator)是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署iterator接口,就可以完成遍历操作。

13、 Iterator 怎么使用?有什么特点?

  1. 创建带一个只针对对象,指向当前数据结构的起始位置
  2. 第一次调用对象next方法,指针自动指向数据结构的第一个成员
  3. 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
  4. 每调用next方法返回一个包含value和done属性的对象

特点

  • (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第
  • 一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
  • (2) 使用next()获得序列中的下一个元素。
  • (3) 使用hasNext()检查序列中是否还有元素。
  • (4) 使用remove()将迭代器新返回的元素删除。

14、 Iterator 和 ListIterator 有什么区别?

  • Iterator 可遍历 Set 和 List 集合; ListIterator 只能遍历 List。
  • Iterator 只能单向遍历;ListIterator 可双向遍历(向前/后遍历)。
  • ListIterator 继承自 Iterator 接口,添加新功能,比如添加一个元素、替换一个元素、获取前面

 15、怎么确保一个集合不能被修改?

可以采用Collections包下的unmodifiableMap方法,通过这个方法返回的map,是不可以修改的。他会报 java.lang.UnsupportedOperationException错。

16、线程和进程的区别?

  • 定义不一样,进程是执行中的一段程序,而一个进程中执行中的每个任务即为一个线程。
  • 一个线程只可以属于一个进程,但一个进程能包含多个线程。
  • 线程无地址空间,它包括在进程的地址空间里。
  • 线程的开销或代价比进程的小。

17、创建线程有哪几种方式?有什么区别?

1.继承thread

  • 定义Thread类的子类,并重写该类的run方法。
  • 创建Thread子类的实例,即创建了线程对象。
  • 调用线程对象的start()方法来启动线程。

2.实现Runnable接口

  • 实现Runnable接口,并重写该接口的run()方法。
  • 创建Runnable实现类的实例,并用该实例作为Thread的target来创建Thread对象,Thread对象才是真正的线程对象。
  • 调用线程对象的start()方法来启动线程。

3.实现Callable接口

实现Callable接口并指定返回值,然后实现call()方法。
创建Callable实现类的实例,使用FutureTask包装类来包装Callable对象。
使用FutureTask对象作为Thread对象的target创建并启动新线程。
调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。

18、 说一下 runnable 和 callable 有什么区别?

相同点:

  • 两者都是接口
  • 两者都需要调用Thread.start启动线程

不同点:

  • 如上面代码所示,callable的核心是call方法,允许返回值,runnable的核心是run方法,没有返回值
  • call方法可以抛出异常,但是run方法不行
  • 因为runnable是java1.1就有了,所以他不存在返回值,后期在java1.5进行了优化,就出现了callable,就有了返回值和抛异常
  • callable和runnable都可以应用于executors。而thread类只支持runnable

19、在 Java 程序中怎么保证多线程的运行安全?

  • 使用手动锁lock
  • 使用线程安全的类
  • 使用自动锁synchronized关键字
  • 使用volatile关键字

20、什么是死锁?

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去;此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

21、多线程产生死锁的 4 个必要条件

  1. 互斥条件:任意时刻一个资源只能给一个进程使用,其他进程若申请一个资源,而该资源被另一进程占有时,则申请者等待直到资源被占有者释放。
  2. 不可剥夺条件:进程所获得的资源在未使用完毕之前,不被其他进程强行剥夺,而只能由获得该资源的进程资源释放。
  3. 请求和保持条件:进程每次申请它所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源。
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

22、 怎么防止死锁?

  • 由于资源互斥是资源使用的固有特性,无法改变,所以我们不讨论。
  • 破坏不可剥夺条件:一个线程不能获得所需要的全部资源时便处于等待状态,等待期间它占有的资源将被隐式的释放,重新加入到系统的资源列表中,可以被其他的线程使用,而等待的线程只有重新获得自己原有的资源以及新申请的资源时才可以重新启动执行。
  • 破坏请求与保持:①第一种方式静态分配即每个线程在开始执行时就申请它所需的全部资源②第二种是动态分配即每个线程在申请所需要的资源时它本身不占用系统资源。
  • 破坏循环等待条件:采用资源有序分配其基本思想是将系统中的所有资源顺序编号,将紧缺的、稀少的采用较大的编号,在申请资源时必须按照编号的顺序进行,一个线程只有获得了较小的编号才能申请较大的编号。

23、synchronized 和 Lock 有什么区别?

  1. synchronized是关键字,Lock是接口;
  2. synchronized是隐式的加锁,lock是显式的加锁;
  3. synchronized可以作用于方法上,lock只能作用于方法块;
  4. synchronized底层采用的是objectMonitor,lock采用的AQS;

24、 sleep() 和 wait() 有什么区别?

1、相同点
sleep()和wait()都可以暂停线程的执行。
2、不同点
所在类不同
sleep()是Thread类的静态方法。
wait()是Object类的方法。

锁释放不同
sleep()是不释放锁的。
wait()是释放锁的。

用途不同
sleep()常用于一定时间内暂停线程执行。
wait()常用于线程间交互和通信。

25、对象的四种引用?

(1)强引用:
强引用只要引用存在,垃圾回收器就永远不会回收。

(2)软引用:
非必须引用,内存溢出之前进行回收

(3)弱引用:
第二次垃圾回收时回收

(4)虚引用:
垃圾回收时回收,无法通过引用取到对象值

26、什么是 Java 序列化?什么情况下需要序列化?

序列化:将 Java 对象转换成字节流的过程。

反序列化:将字节流转换成 Java 对象的过程。

当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。

序列化的实现:类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。

注意事项:

某个类可以被序列化,则其子类也可以被序列化
声明为 static 和 transient 的成员变量,不能被序列化。static 成员变量是描述类级别的属性,transient 表示临时数据
反序列化读取序列化对象的顺序要保持一致

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值