前言
2021 眼看只有一个月就过去了,今年的大厂招聘也已经落幕,不知道你是否拿下自己想要的 offer,不过也不要灰心,接踵而来的是下一波金三银四,这四个月正好是大家储备、刷题的好时机!在这几个月里收到很多粉丝反馈,今年找工作太难了,好不容易有面试邀请,却倒在了前几轮技术面,据了解在大厂面试中基本都会问到下面这套《Java初中级程序员面试题宝典》热门知识点。然而这些知识点在平常工作中有些不一定会经常用到,让许多面试者很是头疼。
在与他们交谈中,问了他们在面试中遇到了哪些问题,经过一个月时间,我把从他们那收集到的问题进行了分类整理,经过多方面资料查阅以及和我朋友 James(阿里 P8)咨询探讨后,最终整理成两份面试笔记《2021 金三银四最新 Java 中高级面试题合集》《2021Java 高级架构面试点解析》;第一份笔记给这些面试问题做了详细的解答;第二份笔记则对于面试问题进行了剖析,分析了面试官考察的动机以及答题时要怎么才能答得完美。
刚整理出来我就迫不及待拿出来给大家分享了。大家是不是要给小编来个赞支持一下^_^
这两份笔记具体咋样,我说了不算,James 说了也不算,只有大家亲自使用之后才能有一个结果。
有需要的伙伴可以私信我领取面试资料宝典!
下面就让我们来揭开这两份笔记的真面目吧。
第一份:2021 金三银四最新 Java 中高级面试题合集
Redis
-
Redis 是什么?都有哪些使用场景?
-
Redis 有哪些功能?
-
Redis 和 memecache 有什么区别?
-
Redis 为什么是单线程的?
-
什么是缓存穿透?怎么解决?
-
Redis 支持的数据类型有哪些?
-
Redis 支持的 java 客户端都有哪些?
-
Jedis 和 Redisson 有哪些区别?
-
怎么保证缓存和数据库数据的一致性?
-
Redis 持久化有几种方式?
-
Redis 怎么实现分布式锁?
-
Redis 分布式锁有什么缺陷?
-
Redis 如何做内存优化?
-
Redis 淘汰策略有哪些?
-
Redis 常见的性能问题有哪些?该如何解决?
-
.......
JVM
-
说一下 jvm 的主要组成部分?及其作用?
-
说一下 jvm 运行时数据区?
-
说一下堆栈的区别?
-
队列和栈是什么?有什么区别?
-
什么是双亲委派模型?
-
说一下类加载的执行过程?
-
怎么判断对象是否可以被回收?
-
java 中都有哪些引用类型?
-
说一下 jvm 有哪些垃圾回收算法?
-
说一下 jvm 有哪些垃圾回收器?
-
详细介绍一下 CMS 垃圾回收器?
-
新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?
-
简述分代垃圾回收器是怎么工作的?
-
说一下 jvm 调优的工具?
-
常用的 jvm 调优的参数都有哪些?
Java基础部分
1.&与&&区别?
&和&&都是逻辑运算符,都是判断两边同时真则为真,否则为假;但是&&当第一个条件不成之后,后面的条件都不执行了,而&则还是继续执行,直到整个条件语句执行完为止。
2.使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
使用 final 关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。
3.静态变量和实例变量的区别?
在语法定义上的区别:
静态变量前要加 static 关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。
静态变量不属于某个实例对象,而是属于类, 所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。
总之,实例变量必须创建对象后才可以通过这个对象 来使用,静态变量则可以直接使用类名来引用。
静态变量使用时,通过类名.名称,实例变量必须要初始化后才能使用。实例变量是实例化后才会分配空间,而静态变量当类加载时会分配空间。
4.是否可以从一个 static 方法内部发出对非 static 方法的调用?
不可以。因为非 static 方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对 象上进行方法调用,而 static 方法调用时不需要创建对象,可以直接调用。也就是说,当一 个 static 方法被调用时,可能还没有创建任何实例对象,如果从一个 static 方法中发出对非 static 方法的调用,那个非 static 方法是关联到哪个对象上的呢?这个逻辑无法成立,所以, 一个 static 方法内部不可以发出对非 static 方法的调用。非static方法可以访问static方法.static方法不能访问非static方法
5."=="和 equals 方法究竟有什么区别?
==如果判断值类型的话,判断内容是否相同。如果判断引用类型则是判断内存地址是否相同
Equals判断值内容是否相等
6.Integer 与 int 的区别
Integer 是引用类型,默认值是null。而int是是值类型默认值是0
7.请说出作用域 public, private, protected,以及不写时的区别
这四个作用域的可见范围如下表所示。
说明:如果在修饰的元素上面没有写任何访问修饰符,则表示 friendly。
作用域 当前类 同一包( package) 子孙类 其他包( package)
public √ √ √ √
protected √ √ √ ×
默认不写 √ √ × ×
private √ × × ×
8.重载与重写区别?
重载是同一个类中,方法名称相同, 但是参数或个数不同。与返回值没有关系。
重写是在多个类中, 产生继承关系。父类与子类的方法必须相同。
9.接口与抽象类的区别?
区别:
①.接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
②.类可以实现很多个接口,但是只能继承一个抽象类
③.类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
④.抽象类可以在不提供接口方法实现的情况下实现接口。
⑤.Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。
⑥.Java接口中的成员函数默认是public的。抽象类的成员函数可以是private,protected或者是public。
⑦.接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含main方法的话是可以被调用的。
10.final, finally, finalize 的区别。
final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量必须定义成 final 类型,例如,一段代码……
finally 是异常处理语句结构的一部分,表示总是执行。
finalize 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可
以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。 JVM 不保证此方法总被
调用
11.String、StringBuffer与StringBuilder的区别
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
12.所有的类都继承于object类,你用过的object类的直接子类有哪些,object类常用的方法有哪些?
①.clone方法
保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
②.getClass方法
final方法,获得运行时类型。
③.toString方法
该方法用得比较多,一般子类都有覆盖。
④.finalize方法
该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
⑤.equals方法
该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。
⑥.hashCode方法
该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
⑦.wait方法
wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。
(1)其他线程调用了该对象的notify方法。
(2)其他线程调用了该对象的notifyAll方法。
(3)其他线程调用了interrupt中断该线程。
(4)时间间隔到了。
此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
⑧.notify方法
该方法唤醒在该对象上等待的某个线程。
⑨.notifyAll方法
该方法唤醒在该对象上等待的所有线程
13.数组有没有length()这个方法? String有没有length()这个方法?
答:数组没有length()这个方法,有length的属性。String有length()这个方法。
14.java 中有几种类型的流?JDK 为每种类型的流提供了一些抽象类以供继承, 为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?
字节流,字符流。字节流继承于 InputStream OutputStream,字符流继承于InputStreamReader OutputStreamWriter。在 java.io 包中还有许多其他的流,主要是为了提高性能和使用方便。
15.error和 exception的区别
Error:表示系统级错误和程序不必处理的异常,是java运行环境中的内部问题或硬件错误。比如:内存资源不足等。对于这种错误,程序基本上无能为力,除了退出程序外别无选择,它是由java虚拟机抛出的。
Exception:表示需要捕捉或程序处理的异常,它处理的是程序设计瑕疵而引起的问题或者在外的输入等引起的一般性问题,是程序必须处理的。
16.说出常见的几种运行时异常(RuntimeException)
①java.lang.NullPointerException (空指针异常)
②java.lang.ClassNotFoundException (指定的类不存在)
③java.lang.ArrayIndexOutOfBoundsException (数组下标越界)
④java.sql.SQLException (Sql语句执行异常 )
⑤java.io.IOException (输入输出异常 )
多线程部分
1.什么是多线程?
在一个应用程序中,同时有多个不同的执行路径。
2.说一下多线程的好处?
提高程序效率。
3.线程和进程有什么区别?
线程是进程的一条执行路径,而进程是线程的集合。
4.什么是线程同步、异步?
线程同步表示,当前线程执行完后下一个线程接着执行。
线程异步表示, 在一个应用程序中,同时有多个不同的执行路径。例如 javaweb ajax android handler
5.线程之间如何同步
线程之间同步使用 synchronized、wait 与 notify
6.什么是线程不安全?如何解决?(重点)
就是在多个线程共享同一个数据会受到其他线程的干扰。如何解决:使用线程同步技术, 用上锁(synchronized)。 让一个线程执行完了,在让另一个线程执行。
7.如何创建一个线程?有几种方法?
继承thread类, 重写run方法、实现Runnalbe接口,重新run方法 , 启动一个线程用start();
8.是使用Runnalbe接口好?还是继承Thread类好?
是实现Runnalbe接口好,因为实现的接口还可以继续继承。如果继承了Thread类不能在继承。
9.sleep()和 wait()有什么区别?
a、sleep是让当前线程指定休眠时间,然后继续工作不释放锁
b、让当前线程wait则是等待,直到有线程通知notify()唤醒他才会重新工作。释放锁
集合相关面试题
1.说一下数据结构中的什么是数组?什么是链表?
所谓数组,是相同数据类型的元素按一定顺序排列的集合
数组:存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;
所谓链表,链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
链表:链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易。
2.说一下ArrayList底层实现方式?
①ArrayList通过数组实现,一旦我们实例化ArrayList无参数构造函数默认为数组初始化长度为10
②add方法底层实现如果增加的元素个数超过了10个,那么ArrayList底层会新生成一个数组,长度为原数组的1.5倍+1,然后将原数组的内容复制到新数组当中,并且后续增加的内容都会放到新数组当中。当新数组无法容纳增加的元素时,重复该过程。是一旦数组超出长度,就开始扩容数组。扩容数组调用的方法 Arrays.copyOf(objArr, objArr.length + 1);
3.说一下LinkedList底层实现方式?
LinkedList底层的数据结构是基于双向循环链表的
4.说一下HashMap底层实现方式?
HashMap是由数组+链表组成
put方法底层实现:
通过key的hash值%Entry[].length得到该存储的下标位置,如果多个key的hash值%Entry[].length 值相同话就就会存储到该链表的后面。
5.ArrayList 和 Vector 的区别
这两个类都实现了 List 接口(List 接口继承了Collection 接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组,我们以后可以按位置索引号取出某个元素,并且其中的数据是允许重复的,
ArrayList 与 Vector 的区别,这主要包括两个方面:.
(1)同步性:
Vector 是线程安全的,也就是说是它的方法之间是线程同步的,而 ArrayList 是线程序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用 ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用 Vector,因为不需要我们自己再去考虑和编写线程安全的代码。
(2)数据增长:
ArrayList 与 Vector 都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要加 ArrayList 与 Vector 的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector 默认增长为原来两倍,而 ArrayList 的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的1.5倍)。
ArrayList 与 Vector 都可以设置初始的空间大小,Vector 还可以设置增长的空间大小,而 ArrayList 没有提供设置增长空间的方法。
6.HashMap 和 Hashtable 的区别
总结:
hashmap | 线程不安全 | 允许有null的键和值 | 效率高一点、 | 方法不是Synchronize的要提供外同步 | 有containsvalue和containsKey方法 | HashMap 是Java1.2 引进的Map interface 的一个实现 | HashMap是Hashtable的轻量级实现 |
hashtable | 线程安全 | 不允许有null的键和值 | 效率稍低、 | 方法是是Synchronize的 | 有contains方法方法 | 、Hashtable 继承于Dictionary 类 | Hashtable 比HashMap 要旧 |
7.List 和Set、Map 区别?
Java中的集合包括三大类,它们是Set、List和Map,它们都处于java.util包中,Set、List和Map都是接口,它们有各自的实现类。Set的实现类主要有HashSet和TreeSet,List的实现类主要有ArrayList,Map的实现类主要有HashMap和TreeMap。
Set中的对象不按特定方式排序,并且没有重复对象。但它的有些实现类能对集合中的对象按特定方式排序,例如TreeSet类,它可以按照默认排序,也可以通过实现java.util.Comparator<Type>接口来自定义排序方式。
List中的对象按照索引位置排序,可以有重复对象,允许按照对象在集合中的索引位置检索对象,如通过list.get(i)方式来获得List集合中的元素。
Map中的每一个元素包含一个键对象和值对象,它们成对出现。键对象不能重复,值对象可以重复。
8.List、Map、Set 三个接口,存取元素时,各有什么特点?
list:存储: 有序的 可重复的
访问:可以for循环,foreach循环,iterator迭代器 迭代。
set:存储:无序的 不重复的
访问:可以foreach循环,iterator迭代器 迭代
map:存储:存储的是一对一对的映射 ”key=value“,key值 是无序,不重复的。value值可重复
访问:可以map中key值转为为set存储,然后迭代这个set,用map.get(key)获取value
也可以 转换为entry对象 用迭代器迭代
9.说出 ArrayList,Vector, LinkedList 的存储性能和特性
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
10.去掉一个 Vector 集合中重复的元素
通过Vector.contains()方法判断是否包含该元素,如果没有包含就添加到新的集合当中,适用于数据较小的情况下。
11.Collection 和 Collections 的区别。
Collection是集合类的上级接口,继承于它的接口主要有Set和List。 Collections是针对集合类的一个帮助类,它提供了一系列静态方法实现了对各种集合的排序,搜索和线程安全等操作。
12.Set 里的元素是不能重复的,那么用什么方法来区分重复与否呢?是用==还是equals()?它们有何区别?
set里的元素是不能重复的,用iterator()方法来区分重复与否。
equals 方法(是String类从它的超类Object中继承的)被用来检测两个对象是否相等,即两个对象的内容是否相等。
==用于比较引用和比较基本数据类型时具有不同的功能:
比较基本数据类型,如果两个值相同,则结果为true
而在比较引用时,如果引用指向内存中的同一对象,结果为true
13.HashMap面试题
总结
HashMap的工作原理
HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。
当两个不同的键对象的hashcode相同时会发生什么? 它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。
因为HashMap的好处非常多,我曾经在电子商务的应用中使用HashMap作为缓存。因为金融领域非常多的运用Java,也出于性能的考虑,我们会经常用到HashMap和ConcurrentHashMap。
14.请讲下Java里面的容器
分两大类,Map和Collection。而Collection又有子接口List(数据存储顺序和插入顺序是一样的)、Set(里面的元素具有唯一性)
Map是存储键值对的,里面的健不可以重复,但值可以重复
a. 对于List主要有ArrayList和LinkedList两种实现。实现的数据结构不同,所以主要的区别也都是和数据结构相关的。 ArrayList基于数组,随机访问快,而对于中间元素的插入删除效率比较低,而且需要考虑扩容问题。LinkedList,则 基于链表,和ArrayList提到的正相反,随机访问慢,但对于中间元素的插入和删除更有效率。
Set也是一种Collection,和List比起来主要体现在元素唯一性。
15.请说下Iterator的作用
迭代器可以实现Collection接口的方法,可以一个一个地获取集合中的元素
在遍历集合时 可判断是否有下一个元素
16.说下ArrayList和LinkedList的区别和联系,并说明什么情况下用它们
区别:
①ArrayList用于对象的随机访问速度快,没有顺序.LinkedList实现机制是链表式的,和顺序有关,速度比ArrayList慢联系:ArrayList和LinkedList都是List接口的实现类
②当要快速获取一个值时,用ArrayList,用于顺序插入操作时,用LinkedList.
17.说下List,Set,Map三种集合各有什么特征
List集合中的元素可以重复,
Set集合中的元素不可以重复
Map集合用键-值映射存放对象,Map容器中的键对象不能重复,值对象可以重复
18.HashSet和TreeSet有什么区别,什么时候用它们
区别:HashSet中的元素不能重复,没有顺序
TreeSet中的元素不能重复,但有顺序
当集合中的元素需要排序时,用TreeSet
一般情况下用HashSet,因为不需要排序,速度比TreeSet快
19.什么是泛型,怎么使用的,有什么好处?
答案
定义一个集合时,可以知道里面定义的是什么类型
使用:在集合类型后面加< 数据类型 >
使用泛型后,从集合中取得元素后就不用再用强转
20.什么是for each循环,它可以循环那些数据类型
答案
也可以叫增强型循环,通过对象拿到集合里的值,因为扩展性比较强,建议多使用
可以用来循环集合和数组
21.比较下集合和数组的优缺点
集合是多个对象的容器,可以将不同数据类型的多个对象组织在一起
数组类型是有相同数据类型的数据集合,数组是很多语言都支持的底层数据结构,性能上是最高的
22.HashMap与LinkedHashMap,和TreeMap的区别。
共同点:HashMap,LinkedHashMap,TreeMap都属于Map的实现类.
不同点:
1.HashMap里面存入的键值对在取出的时候是随机的,
2.TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
3. LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现.
23.在List里面怎么去掉重复的数?
通过把List里面的数据放入HashSet可以去除重复
24.HashMap和ArrayList是不是都是线程不安全的?
ArrayList是线程不安全的;HashMap是线程不安全的;还有我们常见的一些JAVA集合都是线程不安全,这样做是为了提高性能
在JDK5以后提供了线程安全的并发包java.util.concurrent并发包,譬如里面的类CopyOnWriteArrayList,CopyOnWriteArraySet,ConcurrentHashMap等
25.ArrayList集合加入1万条数据,应该怎么提高效率
因为ArrayList的底层是数组实现,并且数组的默认值是10,如果插入10000条要不断的扩容,耗费时间,所以我们调用ArrayList的指定容量的构造器方法ArrayList(int size) 就可以实现不扩容,就提高了性能
说明:本文限于篇幅,故而只展示部分的文档截图,完整的 Java面试学习文档小编已经帮你整理好了,有需要的朋友 可私信我领取资料哦!
分享不易,感谢大家的阅读!