文章目录
一、自我介绍
个人背景、项目经历、实习经历。
二、Java后台
2.1 计算机网络
2.1.1 OSI七层模型
- 物理层:通过媒介传输比特,确定机械及电气规范(比特Bit)
- 数据链路层:将比特组装成帧和点到点的传递(帧Frame)
- 网络层:负责数据包从源到宿的传递和网际互连(包Packet)
- 传输层:提供端到端的可靠报文传递和错误恢复(段Segment)
- 会话层:建立、管理和终止会话(会话协议数据单元SPDU)
- 表示层:对数据进行翻译、加密和压缩(表示协议数据单元PPDU)
- 应用层:允许访问OSI环境的手段(应用协议数据单元APDU)
2.1.2 TCP三次握手
三次握手:(TCP建立连接)
- 第一次握手:客户端发送SYN包(syn=x)的数据包到服务器,并进入
SYN_SEND
状态,等待服务器确认; - 第二次握手:服务器收到SYN包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入
SYN_RECV
状态; - 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入
ESTABLISHED
状态,完成三次握手。
2.1.3 为什么不能两次
采用三次握手是为了防止失效的连接请求报文段突然又传送到主机B,因而产生错误。
失效的连接请求:主机A发出的连接请求没有收到主机B的确认,于是经过一段时间后,主机A又重新向主机B发送连接请求,且建立成功,顺序完成数据传输。主机A第一次发送的连接请求并没有丢失,而延迟到达主机B,主机B以为是主机A又发起的新连接,于是主机B同意连接,并向主机A发回确认,但是此时主机A根本不会理会,主机B就一直等待主机A发送数据,导致主机B的资源浪费。
2.2 Java基础
2.2.1 重载和重写的区别
- 重载 Overload
(1)重载Overload是一个类中多态性的一种表现。
(2)重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序)。
(3)重载的时候,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准 。 - 重写 Override
(1)发生在父类与子类之间。
(2)方法名,参数列表,返回类型必须相同。
(3)访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)。
(4)重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。
2.2.2 JRE和JDK的区别
- JRE:Java Runtime Environment,java运行环境。包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的。所有的Java类库的class文件都在lib目录下,并且都打包成了jar。
- JDK:Java Development Kit,java开发工具包,是程序员使用java语言编写java程序所需的开发工具包。JDK包含了JRE,同时包含了编译java源码的编译器javac,包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,包含了java程序编写所需的文档和demo例子程序。
2.2.3 StringBuilder和StringBuffer的区别
- StringBuilder:线程非安全的,适用于单线程下大量字符串操作的场景。
- StringBuffer:线程安全的,适用于多线程下大量字符串操作的场景。
2.2.4 HashMap
见其他面经:
(1)面试笔记:面经-蚂蚁金服
(2)面试笔记:面经-网易考拉
2.3 多线程
2.3.1 synchronized和volatile
见其他面经:
(1)面试笔记:面经-蚂蚁金服
(2)面试笔记:面经-猿辅导-一面
2.3.2 死锁条件
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不可剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
- 循环等待:若干进程之间形成一种头尾相接的循环等待资源的的关系。
2.3.3 可重入锁
ReentrantLock是一个可重入的互斥(独占)锁,又称为“独占锁”。
ReentrantLock通过自定义队列同步器(AQS,Abstract Queued Sychronized)来实现锁的获取与释放。
- 独占:就是在同一时刻只能有一个线程获取到锁,而其它获取锁的线程只能处于同步队列中等待,只有获取锁的线程释放了锁,后继的线程才能够获取锁。
- 可重入:就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁。
该锁还支持获取锁时的公平和非公平性选择。公平和不公平是指不同的线程获取锁的机制是公平或不公平的。
2.3.4 线程池
线程池:一些线程的集合称为线程池。使用线程池可以提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。
多线程运行时,系统不断的启动和关闭新线程,成本非常高,会过渡消耗系统资源及产生过渡切换线程的危险,从而可能导致系统资源的崩溃。
- Executors.newCacheThreadPool():可缓存的线程池。
- Executors.newFixedThreadPool(int n):指定工作数量的线程池。
- Executors.newScheduledThreadPool(int n):定长线程池,支持定时及周期性任务执行。
- Executors.newSingleThreadExecutor():单线程化的线程池。
2.4 数据库
2.4.1 SQL注入及如何防止
- SQL注入:通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
- 防止SQL注入
(1)采用预编译语句集。
(2)使用正则表达式过滤传入的参数。
(3)字符串过滤。
(4)jsp中调用该函数检查是否包含非法字符。
(5)使用JavaScript在客户端进行不安全字符屏蔽。
三、代码题(手撕)
3.1 SQL语句
stu(name,course,score),查询课程平均成绩大于等于80分的学生姓名及他们的平均分:
select name,avg(score) from stu group by name having avg(score)>=80
3.2 二叉树层次遍历
class TreeNode {
public int data;
public TreeNode left;
public TreeNode right;
public TreeNode(int data) {
this.data = data;
this.left = null;
this.right = null;
}
}
public ArrayList<TreeNode> layerTraverse(TreeNode pRoot) {
ArrayList<TreeNode> list = new ArrayList<>();
if (pRoot == null) {
return list;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(pRoot);
while (!queue.isEmpty()) {
TreeNode n = queue.poll();
list.add(n);
if (n.left != null) {
queue.add(n.left);
}
if (n.right != null) {
queue.add(n.right);
}
}
return list;
}
3.3 二叉树之字形遍历
public ArrayList<ArrayList<Integer>> zigzagTraverse(TreeNode pRoot) {
int layer = 1;
Stack<TreeNode> s1 = new Stack<>();
Stack<TreeNode> s2 = new Stack<>();
// 先将根节点(第一层)入栈s1
s1.push(pRoot);
ArrayList<ArrayList<Integer>> list = new ArrayList<>();
while (!s1.isEmpty() || !s2.isEmpty()) {
// 奇数层
if (layer % 2 != 0) {
ArrayList<Integer> temp = new ArrayList<>();
while (!s1.isEmpty()) {
// 出栈所有结点
TreeNode node = s1.pop();
if (node != null) {
temp.add(node.val);
// 将所有结点的左右子节点从左至右入栈s2
s2.push(node.left);
s2.push(node.right);
}
}
if (!temp.isEmpty()) {
list.add(temp);
layer++;
}
} else {
// 偶数层
ArrayList<Integer> temp = new ArrayList<>();
while (!s2.isEmpty()) {
// 出栈所有结点
TreeNode node = s2.pop();
if (node != null) {
temp.add(node.val);
// 将所有结点的左右子节点从右至左入栈s2
s1.push(node.right);
s1.push(node.left);
}
}
if (!temp.isEmpty()) {
list.add(temp);
layer++;
}
}
}
return list;
}
四、算法题(口述)
1、四亿个int找出重复数(BitMap)。