面试准备-VIP

更多内容请关注:

Java快速开发学习

锁清秋

======================2020=============================

1.简介、兴趣是什么、做过比较有意思的项目是哪个
2.学习
C++
什么是虚函数?什么是纯虚函数?
基类为什么需要虚析构函数?
指针和引用的区别
什么是多态?多态有什么用途?
C++的内存分区
内存泄漏怎么产生的?
Python
Python中如何实现多线程
操作系统
进程和线程以及它们的区别
进程调度算法
进程的常见状态?以及各种状态之间的转换条件?
上下文切换
进程的通信方式
死锁定义、产生条件、预防、解决
内存管理分页和分段有什么区别
计算机组成原理
冯诺依曼结构的特点
高级语言、汇编语言、机器语言之间的关系
编译和解释的区别
缓存淘汰策略
网络
OSI7层模型
TCP和UDP的应用场景
TCP的三次握手
TCP的四次挥手
3.数据结构
链表



4.算法
topn -> 排序 -> 时间复杂度、空间复杂度分析
动态规划
5.java基础
关键字
Java 垃圾回收算法
Java 多线程实现方式
thread类start、run方法
线程安全如何保证
线程池满了会发生什么
concurrenthashmap原理和hashmap的差异
6.组件
mysql
mysql事务隔离级别
乐观锁和悲观锁
索引结构
redis
redis缓存数据一致性
redis快原因
redis持久化
kafka
zookeeper
spring
IOC
AOP
动态代理
maven
jar冲突
7.开放性问题
设计模式
设计模式是什么?为什么需要设计模式?
单例模式:如何保证线程安全、如何保证初始化
举例一个熟悉的设计模式,表述实现方式、适用场景
排查问题思路 功能问题
ut
性能问题
sql
内存
gc
cpu
8.职业规划
1.简介、兴趣是什么、做过比较有意思的项目是哪个
实习时间和频率
是否深入了解项目其他模块内容
是否深入了解项目架构
根据简历内容抽取细节点

2.学习
C++
什么是虚函数?什么是纯虚函数?
虚函数是允许被其子类重新定义的成员函数。
虚函数的声明:virtual returntype func(parameter);引入虚函数的目的是为了动态绑定;
纯虚函数声明:virtual returntype func(parameter)=0;引入纯虚函数是为了派生接口。

基类为什么需要虚析构函数?
防止内存泄漏。想去借助父类指针去销毁子类对象的时候,不能去销毁子类对象。假如没有虚析构函数,释放一个由基类指针指向的派生类对象时,不会触发动态绑定,则只会调用基类的析构函数,不会调用派生类的。派生类中申请的空间则得不到释放导致内存泄漏。

指针和引用的区别
本质上的区别是,指针是一个新的变量,只是这个变量存储的是另一个变量的地址,我们通过访问这个地址来修改变量。
而引用只是一个别名,还是变量本身。对引用进行的任何操作就是对变量本身进行操作,因此以达到修改变量的目的。

什么是多态?多态有什么用途?
静态多态(早绑定)、动态多态(晚绑定)。静态多态是通过函数重载实现的;动态多态是通过虚函数实现的。
1.定义:“一个接口,多种方法”,程序在运行时才决定要调用的函数。
2.实现:C++多态性主要是通过虚函数实现的,虚函数允许子类重写override
注:多态与非多态的实质区别就是函数地址是静态绑定还是动态绑定。如果函数的调用在编译器编译期间就可以确定函数的调用地址,并产生代码,说明地址是静态绑定的;如果函数调用的地址是 需要在运行期间才确定,属于动态绑定。
3.目的:接口重用。封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。
4.用法:声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。
用一句话概括:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。
Overload(重载):在C++程序中,可以将语义、功能相似的几个函数用同一个名字表示,但参数或返回值不同(包括类型、顺序不同),即函数重载。
Override(覆盖或重写):是指派生类函数覆盖基类函数
Overwrite(重写):隐藏,是指派生类的函数屏蔽了与其同名的基类函数
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

C++的内存分区
栈区(stack):主要存放函数参数以及局部变量,由系统自动分配释放。
堆区(heap):由用户通过 malloc/new 手动申请,手动释放。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
全局/静态区:存放全局变量、静态变量;程序结束后由系统释放。
字符串常量区:字符串常量就放在这里,程序结束后由系统释放。
代码区:存放程序的二进制代码。

内存泄漏怎么产生的?
内存泄漏一般是指堆内存的泄漏,也就是程序在运行过程中动态申请的内存空间不再使用后没有及时释放,导致那块内存不能被再次使用。
更广义的内存泄漏还包括未对系统资源的及时释放,比如句柄、socket等没有使用相应的函数释放掉,导致系统资源的浪费。

Python
Python中如何实现多线程
线程是轻量级的进程,多线程允许一次执行多个线程。众所周知,Python 是一种多线程语言,它有一个多线程包。
GIL(全局解释器锁)确保一次执行单个线程。一个线程保存 GIL 并在将其传递给下一个线程之前执行一些操作,这就产生了并行执行的错觉。但实际上,只是线程轮流在 CPU 上。当然,所有传递都会增加执行的开销。

操作系统
进程和线程以及它们的区别
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位,实现了操作系统的并发;
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位,是CPU调度和分派的基本单位,用于保证程序的 实时性,实现进程内部的并发;
一个程序至少有一个进程,一个进程至少有一个线程,线程依赖于进程而存在;
进程在执行过程中拥有独立的内存单元,而多个线程共享进程的内存。

进程调度算法
先来先服务调度算法(FCFS): 作业调度算法或者进程调度算法,按作业或者进程到达的先后顺序依次调度,对于长作业比较有利,但是无法优先处理比较紧急的任务。
短作业优先调度算法(SJF): 作业调度算法,从就绪队列中选择估计时间最短的作业进行处理,直到得出结果或者无法继续执行。所以缺点很明显不利于长作业,没有考虑到部分作业的重要性
优先级调度算法: 优先级越高越先分配到CPU,相同优先级先到先服务,存在的主要问题是:低优先级进程无穷等待CPU,会导致无穷阻塞或饥饿;解决方案:老化
高响应比算法(HRN): 根据响应比决定优先级,响应比=(等待时间+要求服务时间)/要求服务时间
时间片轮转调度(RR): 按到达的先后对进程放入队列中,然后给队首进程分配CPU时间片,时间片用完之后计时器发出中断,暂停当前进程并将其放到队列尾部,以此循环。
多级反馈队列调度算法: 被公认较好的调度算法,设置多个就绪队列并为每个队列设置不同的优先级,第一个队列优先级最高,其余依次递减。优先级越高的队列分配的时间片越短,进程到达之后按FCFS放入第一个队列,如果调度执行后没有完成,那么放到第二个队列尾部等待调度,如果第二次调度仍然没有完成,放入第三队列尾部……只有当前一个队列为空的时候才会去调度下一个队列的进程。

进程的常见状态?以及各种状态之间的转换条件?
就绪:进程已处于准备好运行的状态,即进程已分配到除CPU外的所有必要资源后,只要再获得CPU,便可立即执行。
执行:进程已经获得CPU,程序正在执行状态。
阻塞:正在执行的进程由于发生某事件(如I/O请求、申请缓冲区失败等)暂时无法继续执行的状态。

上下文切换
对于单核单线程CPU而言,在某一时刻只能执行一条CPU指令。上下文切换(Context Switch)是一种将CPU资源从一个进程分配给另一个进程的机制。从用户角度看,计算机能够并行运行多个进程,这恰恰是操作系统通过快速上下文切换造成的结果。在切换的过程中,操作系统需要先存储当前进程的状态(包括内存空间的指针,当前执行完的指令等等),再读入下一个进程的状态,然后执行此进程。

进程的通信方式
管道(pipe)及命名管道(named pipe):管道可用于具有亲缘关系的父子进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
信号(signal):信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
消息队列:消息队列是消息的链接表,它克服了上两种通信方式中信号量有限的缺点,具有写权限得进程可以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息;
共享内存:可以说这是最有用的进程间通信方式。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等;
信号量:主要作为进程之间及同一种进程的不同线程之间得同步和互斥手段;
套接字:这是一种更为一般得进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛

死锁定义、产生条件、预防、解决
在两个或者多个并发进程中,如果每个进程持有某种资源而又等待其它进程释放它或它们现在保持着的资源,在未改变这种状态之前都不能向前推进,称这一组进程产生了死锁。通俗的讲,就是两个或多个进程无限期的阻塞、相互等待的一种状态。
互斥:至少有一个资源必须属于非共享模式,即一次只能被一个进程使用;若其他申请使用该资源,那么申请进程必须等到该资源被释放为止;
占有并等待:一个进程必须占有至少一个资源,并等待另一个资源,而该资源为其他进程所占有;
非抢占:进程不能被抢占,即资源只能被进程在完成任务后自愿释放
循环等待:若干进程之间形成一种头尾相接的环形等待资源关系
死锁预防:只要确保死锁发生的四个必要条件中至少有一个不成立,就能预防死锁的发生
死锁解除:进程终止和资源抢占

内存管理分页和分段有什么区别
段式存储管理是一种符合用户视角的内存分配管理方案。在段式存储管理中,将程序的地址空间划分为若干段(segment),如代码段,数据段,堆栈段;这样每个进程有一个二维地址空间,相互独立,互不干扰。段式管理的优点是:没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)
页式存储管理方案是一种用户视角内存与物理内存相分离的内存分配管理方案。在页式存储管理中,将程序的逻辑地址划分为固定大小的页(page),而物理内存划分为同样大小的帧,程序加载时,可以将任意一页放入内存中任意一个帧,这些帧不必连续,从而实现了离散分离。页式存储管理的优点是:没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满)。
目的不同:分页是由于系统管理的需要而不是用户的需要,它是信息的物理单位;分段的目的是为了能更好地满足用户的需要,它是信息的逻辑单位,它含有一组其意义相对完整的信息;
大小不同:页的大小固定且由系统决定,而段的长度却不固定,由其所完成的功能决定;
地址空间不同: 段向用户提供二维地址空间;页向用户提供的是一维地址空间;
信息共享:段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制;
内存碎片:页式存储管理的优点是没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满);而段式管理的优点是没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)。

计算机组成原理
冯诺依曼结构的特点
计算机由运算器、存储器、控制器、输入输出设备组成
指令和数据以同等地位存储在存储器中,按地址访问
指令数据均用二进制表示
指令顺序存放,顺序执行
以运算器为中心(现代计算机以存储器为中心)

高级语言、汇编语言、机器语言之间的关系
机器语言:(machine code)电脑CPU指令体系(系统)。CPU指令系统中包含大量的由0和1组成的指令码(序列),这些指令码可以直接由计算机识别
汇编语言:由于机器语言复杂庞大很难懂,因此人们在此基础上加入了一些标记符号,在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植
高级语言:虽然汇编语言消除了大量的识别上带来的困难,但依然是很费力的,于是人们再次升级,设计出一种接近人类自然语言(如英语)的语言来描述程序

编译和解释的区别
编译:将源代码转化成目标代码文件,然后执行
编译:前面说到电脑是只能识别机器语言的,而我们更熟悉的是高级语言,也用高级语言来敲代码;因此要让电脑识别我们的指令,则需要将我们敲的高级语言转换成机器语言,这种转换过程称为编译,而转换过程的执行是由编译器来完成(compiler)。通常为了将机器语言和高级语言进行区别,我们将高级语言写的程序称为源文件(或源程序source program)编译之后的机器可以直接辨认并执行的文件称为可执行文件(exe,当然这里经过了链接,见下文),而由0和1构成的机器语言称为目标程序文件(object program)。因此可以将编译进一步定义为:由源程序编译成目标程序的过程。

解释:边翻译边执行,无目标代码文件
解释跟编译很类似,不同之处在于编译是直接一次性生成目标文件(.obj和/或.o文件,即object),而解释则是一条条的解释执行源文件。也因为这种差别,编译型语言(如C/C++、Pascal/Object Pascal(Delphi))生成的目标文件是针对特定CPU体系的,当换一个CPU体系时需要重新编译(如make(编译),make clean(将目标文件.o .obj删除))(引用百科的一句话“用c语言开发了程序后,需要通过编译器把程序编译成机器语言(即计算机识别的二进制文件,因为不同的操作系统计算机识别的二进制文件是不同的),所以c语言程序进行移植后,要重新编译。(如windows编译成ext文件,linux编译成erp文件)”);而解释型语言(如Java、JavaScript、VBScript、Perl、Python、Ruby、MATLAB )等由于是在运行过程中才会被翻译成目标CPU指令,所以在不同CPU体系下都可以执行,不需要重新编译。解释性语言在运行程序的时候才翻译,每个语句都是执行的时候才翻译。这样解释性语言每执行一次就要翻译一次,效率比较低,但跨平台性好。

缓存淘汰策略
随机
FIFO – 先进先出
LFU – 最近最少使用
LRU – 最近最久未使用

网络
OSI7层模型
物理层:RJ45、CLOCK、IEEE802.3 (中继器,集线器,网关)
数据链路:PPP、FR、HDLC、VLAN、MAC (网桥,交换机)
网络层:IP、ICMP、ARP、RARP、OSPF、IPX、RIP、IGRP、 (路由器)
传输层:TCP、UDP、SPX
会话层:NFS、SQL、NETBIOS、RPC
表示层:JPEG、MPEG、ASCII
应用层:FTP、DNS、Telnet、SMTP、HTTP、WWW、NFS

TCP和UDP的应用场景
TCP:当对网络通讯质量有要求的时候,比如:整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。
UDP:当强调传输性能而不是传输的完整性时, 要求网络通讯速度能尽量的快。
TCP-数据流模式、UDP-数据报模式
所谓的“流模式”,是指TCP发送端发送几次数据和接收端接收几次数据是没有必然联系的,比如你通过 TCP连接给另一端发送数据,你只调用了一次 write,发送了100个字节,但是对方可以分10次收完,每次10个字节;你也可以调用10次write,每次10个字节,但是对方可以一次就收完。
原因:这是因为TCP是面向连接的,一个 socket 中收到的数据都是由同一台主机发出,且有序地到达,所以每次读取多少数据都可以。
所谓的“数据报模式”,是指UDP发送端调用了几次 write,接收端必须用相同次数的 read 读完。UDP是基于报文的,在接收的时候,每次最多只能读取一个报文,报文和报文是不会合并的,如果缓冲区小于报文长度,则多出的部分会被丢弃。
原因:这是因为UDP是无连接的,只要知道接收端的 IP 和端口,任何主机都可以向接收端发送数据。 这时候,如果一次能读取超过一个报文的数据, 则会乱套。

TCP的三次握手
三次握手的目的是同步连接双方的序列号和确认号并交换TCP窗口大小信息
(1)首先客户端向服务器端发送一段TCP报文 请求建立新连接,进入SYN-SENT阶段。
(2)服务器端接收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段TCP报文,确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接,服务器端进入SYN-RCVD阶段。
(3)客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段。并返回最后一段TCP报文,确认收到服务器端同意连接的信号,随后客户端进入ESTABLISHED阶段。

TCP的四次挥手
(1)首先客户端想要释放连接,向服务器端发送一段TCP报文,请求释放连接,随后客户端进入FIN-WAIT-1阶段,即半关闭阶段。并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。。
(2)服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文,,随后服务器端开始准备释放服务器端到客户端方向上的连接。客户端收到从服务器端发出的TCP报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段,进入FIN-WAIT-2阶段
前”两次挥手”既让服务器端知道了客户端想要释放连接,也让客户端知道了服务器端了解了自己想要释放连接的请求。于是,可以确认关闭客户端到服务器端方向上的连接了
(3)服务器端自从发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文,已经准备好释放连接了,随后服务器端结束CLOSE-WAIT阶段,进入LAST-ACK阶段。并且停止在服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。
(4)客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文,接收到服务器准备好释放连接的信号,服务器端收到从客户端发出的TCP报文之后结束LAST-ACK阶段,进入CLOSED阶段。由此正式确认关闭服务器端到客户端方向上的连接。

3.数据结构

链表

4.算法
topn -> 排序 -> 时间复杂度、空间复杂度分析

动态规划

5.java基础
关键字
static

Java 垃圾回收算法
Java 多线程实现方式

thread类start、run方法

线程安全如何保证

线程池满了会发生什么

concurrenthashmap原理和hashmap的差异

6.组件
mysql
mysql事务隔离级别

乐观锁和悲观锁

索引结构

redis
redis缓存数据一致性

redis快原因

redis持久化

kafka

zookeeper

spring
IOC

AOP

动态代理

maven
jar冲突

7.开放性问题
设计模式
设计模式是什么?为什么需要设计模式?

单例模式:如何保证线程安全、如何保证初始化

举例一个熟悉的设计模式,表述实现方式、适用场景

排查问题思路
功能问题
ut

性能问题
sql
内存
gc
cpu

8.职业规划
你希望在实习工作中学到什么?

==============================================2017
基础题
hashmap的实现,多线程使用问题

stringBuffer和stringBuilder的区别

乐观锁和悲观锁

如果两个Object是equals的,它们的Hashcode一定相等吗? 反过来如果两个Object Hashcode相同,是否一定equals呢?

如果上题答对,请继续尝试描述Hashtable的实现原理

Java 内存泄露如何定位, 死锁如何定位/修复/预防

请解释什么是泛型,泛型运行时如何获取泛型类型

请解释auto-boxing和auto-unboxing

Checked exception和 Runtime exception的区别是什么?

垃圾收集算法(标记-清除算法、复制算法、标记-整理算法、分代收集算法)

内存分配与回收策略(对象优先在Eden分配,大对象直接进入老年代,长期存活的对象将进入老年代,动态对象年龄判定,空间分配担保)

虚拟机类加载过程(加载,验证,准备,解析,初始化)

类加载模型(双亲类委派加载模型:Bootstrap classloader ->Extension classloader ->Application Classloader ->User classloader)

Tomcat 类加载顺序

OSGI类加载顺序,如果做过Eclipse开发可以询问

字节码生成技术与动态代理的实现

设计模式
你认为为什么需要设计模式

列举设计模式在Java API中的一些应用(Reader接口decorator模式)

开闭原则

常用设计模式(代理、工厂、修饰。。。)

责任链和观察者异同

Spring
spring ioc概念、设计模式作用

spring aop概念、实现(动态代理)

spring context作用

spring mvc概念,如何与servlet规范集成

spring bean生命周期

Java 高并发
Future实现

ConcurrentHashMap 实现

Java Block IO/Non-Block IO/AsynchornusIO(Netty IO 框架使用)

Hiberate
Hibernate 的缺陷是什么?

请解释 Cascade 和 Inverse 这两个关键字

请解释一级缓存和二级缓存的区别

请对 Hiberate和 JPA, iBatis进行比较?

请解释 Hiberante的延迟加载机制

Collection
Comparable 和 Comparator 这两个接口有何不同,各自适用于什么场景

请描述Java Collection的Hierachy, 有哪些接口和哪些实现类,各有什么特点

如果需要对一个List中的对象频繁进行插入和删除操作,请问应该选择哪个实现类

请问 Hashtable 或者 Hashmap 初始化时的 loadfactor 参数是做什么用的?

数据结构
Heap:构建最大堆

Binary Tree:根据先序+终序遍历结果构建二叉树

算法
链表及反转

怎么判断链表上是否存在环

最长递增子串

楼梯有n个台阶,从下往上走,每跨一步只能向上1级或者2级台阶。要求用程序来求出一共有多少种走法。

一个数组长度为n,有一个数字出现次数大于n/2,找出这个数字

已知一个存放正整数的数组,除了一个元素只出现一次,其余的元素都出现了两次,找出这个只出现一次的元素

redis
redis单点问题,如何解决?
redis cluster原理
强一致性?

常用问题
ip库查找

大文件去重

基于redis设计一个分布式锁

设计实现一个基于内存的发布订阅模块

============2020


文章作者: 张文军
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 张文军 !
评论
 上一篇
Mybatis Mybatis
1、什么是Mybatis?(1)Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,
2020-09-21 张文军
下一篇