文章目录
一、自我介绍
个人背景、项目经历、实习经历。
二、项目相关
1、React介绍。
2、SVM介绍。
三、Java后台
3.1 Java异常处理
3.1.1 Exception和Error的区别
Exception和Error都是继承于Throwable类。
- Exception:是java程序运行中
可预料
的异常情况,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。 - Error:是java程序运行中
不可预料
的异常情况,这种异常发生以后,会直接导致JVM不可处理或者不可恢复的情况。所以这种异常不可能抓取到,比如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。
3.1.2 RuntimeException和CheckedException的区别
RuntimeException和CheckedException都继承自Exception类。
- RuntimeException:运行时异常。也称作未检测异常(Unchecked Exception),这表示这种异常不需要编译器来检测。RuntimeException是所有可以在运行时抛出的异常的父类。一个方法除要捕获异常外,如果它执行的时候可能会抛出RuntimeException的子类,那么它就不需要用throw语句来声明抛出的异常。 例如:NullPointerException,ArrayIndexOutOfBoundsException等等
- CheckedException:受检查异常。是编译器在编译时进行校验的,通过
throws语句
或者try{}cathch{}语句块
来处理检测异常。编译器会分析哪些异常会在执行一个方法或者构造函数的时候抛出。
3.2 Java线程
3.2.1 sychronized
synchronized的特点是自动释放锁,作用在方法时自动获取锁,任意对象都可做为锁,它是最常用的加锁机制。
synchronized可以手动指定锁,当作用在方法时会自动获取锁:
- 作用于普通方法获得当前对象锁,等价于synchronized(this)。
- 作用于静态方法获得类锁,等价于synchronized(类.class)。
3.2.2 Lock
Lock的特点是必须自己创建锁(锁类型已经指定为Lock的实现类,不能使用其它对象),必须自己释放锁。
一定要在finally中释放锁,保证即便抛出异常也可以释放。
3.2.3 volatile
volatile是稍微弱一点的同步机制,主要就是用于将变量的更新操作通知到其它线程。volatile变量是一种比sychronized关键字更轻量级的同步机制。声明变量是volatile的,JVM保证每次读变量都从内存中读,跳过CPU cache这一步。
四、算法题(手撕)
4.1 以X为基准分割链表
以给定X为基准将链表分割为两部分,所有小于X的节点排在大于等于节点之前,并且保持原来顺序基本不变。
public static Node partition(Node head, int x) {
if (head == null) {
return null;
}
Node small = null;
Node big = null;
Node smallTail = null;
Node bigTail = null;
for (Node cur = head; cur != null; cur = cur.next) {
if (cur.value < x) {
if (small == null) {
small = cur;
} else {
smallTail.next = cur;
}
smallTail = cur;
} else {
if (big == null) {
big = cur;
} else {
bigTail.next = cur;
}
bigTail = cur;
}
}
if (small == null) {
return big;
} else {
smallTail.next = big;
if (bigTail != null) {
bigTail.next = null;
}
return small;
}
}
4.2 逆时针打印二叉树边缘
public static void getLeftSizeNodes(TreeNode root) {//遍历左边缘节点
TreeNode node = root;
while (node != null) {
list.add(node);
node = node.left;
}
}
public static void getBottomSizeNodes(TreeNode root) {//遍历底层叶子节点
TreeNode node = root;
if (node == null) {//根节点为空
return;
}
getBottomSizeNodes(node.left);//递归根节点的左子树
if (node.left == null && node.right == null) {//如果当前节点是叶子节点
if (list.get(list.size() - 1) != node) {
list.add(node);
}
return;
}
getBottomSizeNodes(node.right);//递归根节点的右子树
}
public static void getRightSizeNodes(TreeNode root) {//遍历右边缘节点
TreeNode node = root;
Stack<TreeNode> stack = new Stack<TreeNode>();//因为右边缘节点需要从下往上打印所以要用到栈
node = node.right;
while (node != null) {//遍历根节点的右子树及其右子树的右子树
stack.push(node);//非空则压栈
node = node.right;
}
while (!stack.isEmpty()) {
TreeNode n = stack.pop();//出栈
if (list.get(list.size() - 1 ) != n) {
list.add(n);
}
}
}