
面试要点(中)
本文最后更新于 2024-11-21,文章内容可能已经过时。
39-创建线程池的方式以及作用
newCacheThreadPool:缓存可重复利用;
newFixedThreadPool:可重复固定线程数的线程池;
newSingleThreadExecutor:创建一个使用单个worker线程的线程池,以无界队列来运行;
newSingleThreadScheduledExecutor:创建一个单线程,可以在给定延迟后运行命令,或者定期执行;
newScheduledThreadPool:创建一个线程池,可以在给定延迟后运行命令,或者定期执行;
newWorkStealingPool:创建一个带并行级别的线程池。
40-字符串以及数字的反转
public class ReverseString {
public static void main(String[] args) {
String originalString = "Hello, World!";
String reversedString = new StringBuilder(originalString).reverse().toString();
System.out.println("Original String: " + originalString);
System.out.println("Reversed String: " + reversedString);
}
}
41-oss和fastdfs的区别
oss:高稳定性和高可靠性,但是相比于fastdfs在高并发场景存在瓶颈;维护成本高;适用于在不同地域配置数据中心。
fastdfs:是基于HTTP协议实现的,具有非常快的上传,下载,传输速度,能够处理数千并发请求;可自行搭建;适用于自行管理文件存储和访问,或者高并发文件存储和访问场景。
42-一直点击朋友圈喜欢怎么保证不出问题
可以加个时间间隔,或者设置一个token验证
43-nginx如何实现负载均衡
什么是负载均衡:负载均衡就是代理服务器将接受的请求均衡的分发到各个服务器中。
轮询,最少连接数,加权,ip哈希。
定义一组后端服务器,配置负载均衡算法,配置代理服务器,健康检查。
44-cookie和session的区别
cookie:存放在本地磁盘中;单个保存数据小于等于4kb,一个站点最大保存20个cookie;只能保管ASCII字符本地可见的存储在服务器;可设置长久有效;不占用服务器资源
session:存放在服务器对象;存储没上限;能存储任何数据;不可见;每次关闭窗口,session会实效。占用服务器资源。
45-springmvc注解的作用
@RequestMapping("/AAA")放在类上,是父接口(url/路径)
....(@RequestBody AAA bbb)将前端json转换为后端java对象(放在变量前)
@ResponseBody将后端java对象转换为json数据(放在类|方法上)
.....(.../{bbb}) .....(@PathVarible AAA aaa)从某个路径上获取参数
aaa@ControllerAdvice声明该类是一个全局异常处理类
@ExceptionHandler(aaa.class)用在异常处理类中的某个方法上,标记这个方法是用来处理哪种异常的。
46-rocketmq如何保证消息不丢失
消息生产者端:采取send()同步发送消息。设置发送失败后重试次数。采用集群部署。
broker端:修改刷盘策略为异步刷盘;集群部署。
消费者端:完全消费后进行手动ack确认。
47-tcp和udp的区别
TCP:面向连接,传输可靠,适用于少量数据传输;
UDP:面向非连接,不可靠,大量数据速度慢快。
48-事务的特性
ACID:原子性,一致性,隔离性和持久性。
A:不可被分割,要么全部执行,要么全部不执行;
C:一种正确状态转化为另一种正确状态;
I:在一个事务提交之前,不允许把该事务对数据的任何改变提供给其他事务;
D:事务提交后就永久保存在数据库中,即使在提交之后有了故障也不影响。
49-常见的异常
运行时异常和编译时异常。
运行时异常:程序逻辑错误引起,不处理也会编译通过(java编译器不检查)。空指针异常,类型强制转换异常,数组下标越界异常等。都是RuntimeException类及其子类。
编译时异常:除了RuntimeException的都是,必须处理,否则编译不通过。比如:IOException,SQLException以及自己定义的异常(一般不建议自定义)。都是Exception类及其子类。
50-重载和重写
重载:发生在同一个类中,方法名必须相同,参数列表必须不同,返回值和访问修饰符没有要求。发生在编译时。
重写:发生在父子类中,方法名和参数列表必须相同,返回值和异常范围小于等于父类,访问修饰符必须大于等于父类。
51-单例模式
单例模式:某个类的实例在多线程中只会被创建一次。
饿汉式:初始是初始化。安全
懒汉式:延迟初始化,不安全
......{
private static Singleton instance;
private intance(){}
private Singleton getInstance(){
if(instance ==null){
instance=new Singleton();
}
return instance;
}
}
双检索:延迟初始化,安全。
52-数据库的优化
定位执行效率慢的sql语句;
避免索引失效;
sql语句调优;
合理的数据库设计。
53-sql优化
根据业务建立复合索引只查询业务需要的字段;
多表连接的字段上可建立索引;
where条件上建立索引;
优化insert语句进行批量插入;
使用order by时不用select *,只需要查询需要排序的,尽量同时升降序;
分组是默认为降序,当不用可以进行order by null禁用;
尽量避免子查询。
54-数据库的死锁以及如何避免
死锁:
指两个或者多个事务在执行过程中,由于互相等待对方持有的资源,导致所有事务都无法继续执行。
解决:
按照同一顺序访问对象;
使用较低的隔离级别,比如读写未提交;
使用索引;
避免长事务,尽量缩短事务的执行时间;
优化查询语句,减少不必要的访问;
使用行锁;
使用乐观锁;
定期检查处理。
55-主键,外键的区别,索引的好坏
主键:每条数据的唯一标识,不可为空,唯一,不可重复,不可改变。primary key
外键:用于建立各个表之间的联系,一个外键关联另一个的主键。
索引的优点:
加快数据检索/查询速度,最主要的;
加速表和表之间的连接;
提高分组效率;
减少排序成本。
缺点:
占用空间;增加维护成本;不合理的索引设计会降低查询速度。
56-如何避免索引失效
模糊查询时,左边的列不能使用索引,否则右边也会失效;
索引上不可进行运算;
字符串索引不加引号会失效;
避免使用select *;
or 连接字左右同时有。
57-mysql单表上限,索引上限
mysql底层是B+数存储。
单表上限不建议超过2000万,索引一张表最多支持64个。
58-数据库两种引擎
MyISAM:mysql5.5所支持引擎,支持表锁,不支持事务。
InnoDB:5.5以后的引擎,支持行锁,支持事务。
59-介绍一下隔离级别解决什么事以及幻读是什么,怎么解决的
读取未提交:所有的事务都可以读取到其他事务未提交的数据。会产生脏读。
读取已提交:大多数数据库默认级别。解决脏读,只能看见已提交的事务。会产生不可重复读问题。
可重复读:mysql的默认级别。会产生幻读。幻读:当用户读取某一范围的数据行时,另一个事务又在该范围内插入新行,再读取时就会出现新行。通过多版本并发控制mvcc机制解决。
可串行化:强制事务排序,使之不可能互相冲突。
60-数据库的主从复制以及分库分表
主从复制:将主库的数据复制到其他从库中。优点:数据备份,读写分离,数据一致性,扩展性。
分库分表:将一个数据库|表,分解到多个库|表中。为了提高性能,保证数据安全,但也会导致事务性问题和表连接问题。
61-索引
分类:普通索引,唯一索引,主键索引,联合索引,全文索引。
62-&&和&的区别
&&:逻辑运算符,具有短路行为,左边为false,右边不进行运算
&:既是位运算符,也是逻辑运算符,不具有短路行为,左边不影响右边。
63-垃圾回收机制
分为两大部:如何发现垃圾,如何处理垃圾。
注意:线程私有的不存在gc,只有共享的堆才有gc。
如何发现垃圾:引用计数算法,根搜索算法
如何处理垃圾:标记-复制算法,标记-清楚算法,复制算法,分代收集算法
64-char和varchar的区别
char:长度固定;存储空间分配固定,如果存储字符小于定长,会造成空间浪费;最大长度为255字符;存储时会删除空格;处理数据时效性高。
varchar变长;只存储实例需要的字符加一个额外的字节;动态分布;65535;存储时保留空格;处理数据时效性低。
65-除了atowaird注入,还有哪种注入
@Atowaird:可以放在属性或者方法上,先根据类型注入,若存在多个属性相同的对象,会按照属性名注入;如果放在方法上,表示自动执行当前方法,如果有参数,会自动从ioc容器中寻找同类型的对象给参数传值。
@Resource:只能放在属性上,先按照属性名匹配ioc容器中对象,没成功根据当前属性类型匹配。也可以@Resource(name="对象id"),根据对象id注入。
66-素数
public class PrimeChecker {
public static void main(String[] args) {
int number = 29; // 你可以改变这个数来测试不同的值
if (isPrime(number)) {
System.out.println(number + " 是素数。");
} else {
System.out.println(number + " 不是素数。");
}
}
public static boolean isPrime(int num) {
// 小于等于1的数不是素数
if (num <= 1) {
return false;
}
// 检查从2到sqrt(num)的所有数是否能整除num
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) {
return false; // 如果找到一个因子,则num不是素数
}
}
return true; // 没有找到因子,num是素数
}
}
sqrt指得是非负平方根。
67-反射
反射:在运行状态中,对于任意一个类能够知道这个类所有的属性和方法;并且对任意一个对象,都能够调用它的任意一个方法。
68-获取Class对象
调用某个对象的getClass方法:
AAA aaa=new AAA();
Class c1=aaa.getClass();
调用某个类的class属性:
Class c2=类C.class;
使用class类中的forname方法:
Class c3=Class.forname("类的全路径");(最常用)
69-如何用反射拿到类的所有public
先过去类的class对象,然后再通过调用class对象的getMethods()方法来获取类的所有public,包括所继承的方法。(一般用数组接受,最后遍历输出就行)
70-java是不是可跨平台的
是
71-int与integer比较
int:基本类型,默认值为0,存储在栈中,不需要实例化,==;
integer:引用类型,默认值null,堆中,必须实例化(new Integer/Integer.valueof),equlas。
二者之间可以自动拆装箱,自行转换。
72-int与integer==的比较
int a=10,Integer b=10,Integer c=new Integer(10),Integer d=Integer.valueof(10)
Integer f=10;
a==b,true,integer会自动拆箱
a==c,false
c==d,false,因为两个是对象是通过new比较。
b==c,false
b==f,true,在范围内为true,之外为false
73-介绍springapplication
@SpringBootConfiguration+@EnableAutoConfiguration+@ComponentScan
配置类+自动导入+包扫描
74-reds中rdb是不是默认开启的,如何开启,宕机之后哪种恢复的快
是默认开启的,redis的配置文件为redis.conf
rdb快,但是aof更完整
75-new String("xyz")创建了几个对象
两个,一个放在堆中,一个放在常量池中。
76-final
修饰类:该类不可被继承
修饰方法:该方法不可被重写
修饰变量:变量不可被更改
77-反射的应用
获取Class对象,获取成员变量getFields(),获取构造方法getConstructors,获取所有public方法。
78-io流
分为输入输出流(Input/Output)。
缓冲流作用:
降低io操作所消耗性能,缓冲流将数据加载到缓冲区,一次性读取或者写入多个字节,从而避免频繁的io操作,提高流的输就效率。
注意:
常用的sout底层就是print调用的是PrintStream的write方法,字节输出流。
音视频文件,图片一般采用字节流形式。
79-zookeeper应用场景
统一命名服务,统一配置管理,统一集群管理,集群选主,分布式锁。
80-布尔默认值
false
81-map有几个线程安全的
hashtable和ConcurrentHashMap
82-快速排序
public class QuickSort {
// 主方法,用于测试
public static void main(String[] args) {
int[] array = {10, 7, 8, 9, 1, 5};
int n = array.length;
QuickSort ob = new QuickSort();
ob.quickSort(array, 0, n - 1);
System.out.println("排序后的数组:");
printArray(array);
}
// 快速排序方法
void quickSort(int[] array, int low, int high) {
if (low < high) {
// pi 是分区索引,array[pi] 已经在正确位置
int pi = partition(array, low, high);
// 分别对左右子数组进行快速排序
quickSort(array, low, pi - 1);
quickSort(array, pi + 1, high);
}
}
// 分区方法
int partition(int[] array, int low, int high) {
int pivot = array[high]; // 选择最右边的元素作为基准
int i = (low - 1); // i 是较小元素的索引
for (int j = low; j < high; j++) {
// 如果当前元素小于或等于基准
if (array[j] <= pivot) {
i++;
// 交换 array[i] 和 array[j]
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
83-手撕代码:翻转队列
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
public class ReverseQueue {
public static void main(String[] args) {
// 创建一个队列并添加一些元素
Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.add(2);
queue.add(3);
queue.add(4);
queue.add(5);
System.out.println("Original Queue: " + queue);
// 调用反转队列的方法
Queue<Integer> reversedQueue = reverseQueue(queue);
System.out.println("Reversed Queue: " + reversedQueue);
}
public static Queue<Integer> reverseQueue(Queue<Integer> queue) {
// 创建一个栈来辅助反转
Stack<Integer> stack = new Stack<>();
// 将队列中的所有元素压入栈中
while (!queue.isEmpty()) {
stack.push(queue.poll());
}
// 创建一个新的队列来存储反转后的元素
Queue<Integer> reversedQueue = new LinkedList<>();
// 将栈中的所有元素依次弹出并添加到新队列中
while (!stack.isEmpty()) {
reversedQueue.add(stack.pop());
}
return reversedQueue;
}
}
// 交换 array[i + 1] 和 array[high] (或基准)
int temp = array[i + 1];
array[i + 1] = array[high];
array[high] = temp;
return i + 1;
}
// 打印数组的方法
static void printArray(int[] array) {
int n = array.length;
for (int i = 0; i < n; ++i)
System.out.print(array[i] + " ");
System.out.println();
}
}