Java面试题(9问)
1. 列举java的常用容器(集合)
有Collection接口下的List、Queue、Set
还有Map接口下的HashMap、HashTable等
2. List和Set的区别,不可重复是什么意思?
(1)List可以有重复的对象,而Set不允许有重复的对象
(2)List可以插入多个null元素,而Set只允许有一个null元素
(3)List是一个有序的容器,按照对象进入的顺序存储。而Set是无序容器,无法保证每个元素的存储顺序,使用哈希表存储。
不可重复:使用hashcode和equals方法来判断,如果没有重写hashcode方法和equals方法,则会根据对象的hashcode找到对应的地址,如果此地址没有元素,则直接存储。如果此地址已经存在元素,则会调用equals方法判断是否相等,相等的话就代表重复,不会存储,不相等即代表不重复,重新产生hashcode(找一个其他地址存储)
3. HashMap是否线程安全,如果想用线程安全的HashMap怎么做?
HashMap线程不安全
1 、可以使用HashTable,HashTable中使用了synchronized来保证线程安全,但是效率较低。
2、可以使用ConcurrentHashMap,ConcurrentHashMap是Java 中支持高并发,高吞吐量的hashMap实现。ConcurrentHashMap避免了对整个Map进行加锁,从而提高了效率
4. 编写一个单例模式,常见的单例有哪些,分别列举?
懒汉模式:
饿汉模式:
枚举:
5. 有哪些排序算法,写出快速排序算法的实现
经典的排序算法有:冒泡排序、选择排序、插入排序、快速排序等。
https://blog.youkuaiyun.com/qwserft/article/details/115691086
快速排序算法实现:
public static void QuickSort(int[] arr,int left,int right) {
if(left > right) {
return;
}
int base = arr[left];//选取数组第一个元素为基准
int i = left;
int j = right;
while (i != j) {
//先从右向左找到比base小的数
while(arr[j] >= base && j > i) {
j--;
}
//再从左往右找到比base大的数
while (arr[i] <= base && i < j) {
i++;
}
//交换两个数的位置
if(i < j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
//以上循环结束后i和j相遇,即都走到了数组的中间位置
//将基准数放到中间位置(基数归位)
arr[left] = arr[i];
arr[i] = base;
//继续对基准的两边执行以上操作
QuickSort(arr, left, i-1);//基准左边的子数组
QuickSort(arr, i+1, right);//基准右边的子数组
}
测试结果:
6. 给一个二叉树,使用递归和非递归完成先序,中序和后序的遍历
先序:根左右
递归:
public void preOrder(TreeNode root) {
if(root == null) {
return;
}
System.out.println(root.val);
PreSort(root.left);
PreSort(root.right);
}
非递归:
public void preOrder(TreeNode root) {
Stack<TreeNode> stack=new Stack<>();
TreeNode currNode=root;
if(currNode!=null) {
stack.push(currNode);
while(!stack.isEmpty()) {
currNode=stack.pop();
System.out.print(currNode.val+" ");//根节点
if(currNode.right!=null) {
stack.push(currNode.right);//右节点
}
if(currNode.left!=null) {
stack.push(currNode.left);//左节点
}
}
}
}
中序:左根右
递归:
public void inOrder(TreeNode root) {
if(root == null) {
return;
}
PreSort(root.left);
System.out.println(root.val);
PreSort(root.right);
}
非递归:
public void inOrder(TreeNode root) {
Stack<TreeNode> stack=new Stack<>();
TreeNode currNode=root;
while(currNode!=null||!stack.isEmpty()) {
while(currNode!=null) {
stack.push(currNode);
currNode=currNode.left;
}
if(!stack.isEmpty()) {
currNode=stack.pop();
System.out.print(currNode.val+" ");
currNode=currNode.right;
}
}
}
后序:
递归:
public void postOrder(TreeNode root) {
if(root == null) {
return;
}
PreSort(root.left);
PreSort(root.right);
System.out.println(root.val);
}
非递归:
public void postOrder(TreeNode root) {
Stack<TreeNode> stack1=new Stack<>();
Stack<TreeNode> stack2=new Stack<>();
TreeNode currNode=root;
while(currNode!=null||!stack1.isEmpty()) {
while(currNode!=null) {
stack1.push(currNode);
stack2.push(currNode);
currNode=currNode.right;
}
if(!stack1.isEmpty()) {
currNode=stack1.pop();
currNode=currNode.left;
}
}
while(!stack2.isEmpty()) {
currNode=stack2.pop();
System.out.print(currNode.val+" ");
}
}
7. 数据库的事务的四大特性及数据库的隔离级别
数据库事务的四大特性:
1、原子性
指事务中包含的所有操作要么不做,要么全做。
2、隔离性
指多个用户并发访问数据库时,每个用户所进行的操作都不被其他用户所干扰,事务之间相互隔离。
3、一致性
指数据库中的数据在事务操作前和操作后都必须满足业务规则约束。事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
4、持久性
指事务一旦被提交,其对数据库中的数据的改变是永久性的。
隔离级别:
1、读未提交:
在其中一个事务中可以读取到其他事务没有提交的数据变化,会产生脏读问题。
2、读已提交:
在其中一个事务中可以读取到其他事务已经提交的数据变化,会产生不可重复读问题
3、可重复读:
在其中一个事务中,直到事务结束前,都可以反复读取到事务刚开始时看到的数据,并且一直都不会发生变化,避免了脏读、不可重复读。
4、串行:
在每个读的数据行上都需要加上表级共享锁,在每次写数据时都要加上表级排他锁。
8.TCP的三次握手和四次挥手
详细见此篇博客:
https://blog.youkuaiyun.com/qwserft/article/details/118685969
9. GET/POST的区别,除了GET/POST还有哪些?
1、get不安全,因为在传输的过程中,数据被放在URL中。而post的所有操作对用户都是不可见的。
2、get由于受url长度的限制,传输的数据量小。而post一般被默认为不受限制。
3、get的效率比post更好。
除了GET/POST还有:
head:类似于get请求,用于获取报头,返回的响应中没有具体内容
put:从客户端向服务器传送的数据取代指定的文档的内容,向指定资源位置上传其最新内容
delete:请求服务器删除指定的页面
connect:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
options:允许客户端查看服务器的性能
trace:回显服务器收到的请求,主要用于测试或诊断