37、说说数据库设计三范式?
第一范式
属性(字段)的原子性约束,要求属性具有原子性,不可再分割; 比如个人信息,个人信息不能作为一个字段,它可以再分为姓名、name、age等;
第二范式
记录的惟一性约束,要求记录有惟一标识,每条记录需要有一个属性来做为实体的唯一标识;
第三范式
字段冗余性的约束,即任何字段不能由其他字段派生出来;主键没有直接关系的数据列必须消除,消除的办法就是再创建一个表来存放他们,当然外键除外;
误区:
并不是非得严格按照三范式来设计,好的数据库设计一定不是这样的,而是根据实际情况柔性处理;
38、简单阐述Java中的io、nio、bio
i/o即input/output,就是指读写操作
面试官经常问io和nio的区别,如果把io和nio放一起比较的话,那这里的io其实可以理解为bio,即blocking-io:
bio:同步阻塞
bio是java传统的io模型,他是同步阻塞io,一个线程触发io操作后,必须等待这个io操作执行完成,期间不能去做其他事情;
nio:同步非阻塞
nio(non-blocking-io)是同步非阻塞io,一个线程触发io操作后它可以立即返回,但是他需要不断地轮询去获取返回结果;
aio:异步非阻塞
aio(Asynchronous-io)是异步非阻塞io,一个线程触发io操作后她可以立马返回去做其他事情,内核系统将io操作执行完成后会通知线程;
多路复用io:异步阻塞
io多路复用:可以理解为异步阻塞io,但官方没这么叫,一个线程可以管理多个连接,不用来回切换;
39、什么是内存泄漏,怎么确定内存泄漏?
概念:内存泄漏就是指jvm内存没有及时释放,用人话说就是使用完的对象没有被及时回收
怎么确认:linux有个工具叫valgrind,一两句话说不清楚,单独拎出来讲,移步使用valgrind来检查内存泄漏
40、实现单例设计模式(懒汉、饿汉)
//懒汉,顾名思义比较懒,在用的时候才实例化
public class Singleton {
//创建实例,注意,此时没有new
private static volatile Singleton instance = null;
//构造方法私有化,无法在外部获取实例,只能通过下方的公有静态方法
private Singleton() {}
//公有的静态方法,返回实例对象
public static synchronized Singleton getInstance() {
//先看下是否存在实例,有的话就不再new了
if (instance == null) {
//这里才new
instance = new Singleton();
}
return instance;
}
}
//饿汉,顾名思义很饥饿,创建对象的时候就直接new
public class Singleton {
//创建实例的时候就new
private static Singleton instance = new Singleton();
// 私有化构造方法,外部不能new
private Singleton() {}
//公有的静态方法,返回实例对象
public static Singleton getInstance() {
//直接将事先new好的实例返回
return instance;
}
}
41、手写生产者消费者模型
生产者消费者是并发编程很经典的一个模型
牵涉三个对象:仓库、生产者、消费者
仓库:代表共享变量
生产者:表示在仓库生产货物
消费者:表示从仓库拿出货物
实现思路:线程间通信
具体demo请见一看就懂的生产者消费者模型
42、int和Integer有什么区别?
int是基本数据类型,默认值为0,integer是其包装类型,默认值为null
- 原始类型: boolean,char,byte,short,int,long,float,double
- 包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double
java实体类尽量都用integer,假设一个学生类,有个考试成绩属性,如果学生缺考,该属性不应该有值,应该为null,你用int的话默认值为0,考试成绩为0和缺考是两码事
43、String和StringBuilder、StringBuffer的区别?
Java平台提供了两种类型的字符串:String和StringBuffer/StringBuilder,它们可以储存和操作字符串。其中String是只读字符串,也就意味着String引用的字符串内容是不能被改变的。而StringBuffer/StringBuilder类表示的字符串对象可以直接进行修改。StringBuilder是Java 5中引入的,它和StringBuffer的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方面都没有被synchronized修饰,因此它的效率也比StringBuffer要高。
44、常见的运行时异常
- ArithmeticException(算术异常)
- ClassCastException (类转换异常)
- IllegalArgumentException (非法参数异常)
- IndexOutOfBoundsException (下标越界异常)
- NullPointerException (空指针异常)
- SecurityException (安全异常)
45、事务的ACID是指什么?
- 原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;
- 一致性(Consistent):事务结束后系统状态是一致的;
- 隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;
- 持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败,通过日志和同步备份可以在故障发生后重建数据。
46、事务隔离级别
1、READ_UNCOMMITTED
读未提交,即能够读取到没有被提交的数据,无法解决脏读、不可重复读、幻读
2、READ_COMMITED
读已提交,即能够读到那些已经提交的数据,能够防止脏读,但是无法限制不可重复读和幻读
3、REPEATABLE_READ
可重复读,即在数据读出来之后加锁,类似"select * from XXX for update",明确数据读取出来就是为了更新用的,所以要加一把锁,防止别人修改它。REPEATABLE_READ的意思也类似,读取了一条数据,这个事务不结束,别的事务就不可以改这条记录,这样就解决了脏读、不可重复读的问题,但是幻读的问题还是无法解决
4、SERLALIZABLE
串行化,最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务,解决了脏读、不可重复读和幻读
表格总结
47、悲观锁和乐观锁的原理以及应用场景
悲观锁:
顾名思义,比较悲观,每次去拿数据都认为别人会修改,所有每次在操作前都会加锁,如:读写锁、行锁、表锁等,synchronized的原理也是悲观锁;适用于多写操作
乐观锁:
每次拿数据都认为别人不会修改,所以不会加锁,但是在更新的时候,会先判断在此期间有没有人更新该数据,如果有,返回冲突报错信息,让用户决定怎么操作;适用于多读操作
48、对spring IOC和AOP的理解
IOC(控制反转)
也叫DI(依赖注入),是一种思想,不是一种技术,IOC主张把对象的控制权交由spring,底层实现是反射+工厂方法模式,IOC容器实际上就是个Map,存放各种对象;
AOP
面向切面编程,把一些能共用、冗余、繁琐的功能提取出来,AOP能在不改变原有业务逻辑的情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复;常见使用场景有事务管理、日志、全局异常处理、用户鉴权;
49、简述java内存模型
注意和本文23点的jvm内存模型区分开,这是两种截然不同的内存模型
以下是本人总结的概念,别看字多,都是精华,我想过删些,一句都没找到,阅读一遍应该理解的差不多了
-
java内存模型的由来:这和cpu和内存技术发展有关,当代cpu运算速度太快,以至于被内存拉低了程序运行的整体效率
-
应对措施:为了不被内存影响性能,cpu厂商给cpu加了一级二级甚至三级高速缓存,cpu读取数据时先从一级缓存中找,没有的话找二级,再没有就找三级或者主存;java内存模型规定了变量都是存储在主存中,程序运行时操作的是高速缓存中的数据,操作完之后再同步到主存;
-
后遗症及规范:在cpu和主存之间增加了一个高速缓存固然提升了程序运行效率,但是在多线程并发操作同一个变量时,就可能造成数据不一致的问题,所以就有了JMM(java内存模型,也可叫JMM规范),它保证了并发编程中数据的正确性(正确性可细分为原子性、可见性、有序性),底层具体实现方式比较复杂,好在JMM为我们日常编程提供了一些用于保证数据正确性的关键字,如synchronized(原子性、有序性)、volatile(可见性、有序性);
50、什么是泛型擦除?
泛型只是为了在编码过程中,我的理解是泛型存在的意义有两个:一是为了让我们更快地发现错误,比如你把User放进了ArrayList< Dog >中,编译器立马会报错;二是避免类型检查,从而避免在运行时抛出 classCastException;泛型擦除就是指泛型会在编译时被消除
ArrayList users = new ArrayList<>();
ArrayList dogs = new ArrayList<>();
System.out.println(users.getClass() == dogs.getClass());
//true
如上,运行结果表面两个list是相等的,因为经过编译后,泛型被擦除,两个list当然也就相等;
51、你能想到几种方法实现两数交换?
1、第三变量
public void swapOne(){
int a = 4;
int b = 5;
int c = a;
a = b;
b = c;
System.out.println(“a:”+a); //a:5
System.out.println(“b:”+b); //a:4
}
2、数学计算
public void swapTwo(){
int a = 4;
int b = 5;
a=a+b;
b=a-b;
a=a-b;
System.out.println(“a:”+a); //a:5
System.out.println(“b:”+b); //a:4
}
3、异或运算
public void swapThree(){
int a = 4;
int b = 5;
a = a ^ b; // 0101 ^ 0100 ===> 0001,此时a的值为1
b = a ^ b; // 0001 ^ 0100 ===> 0101,此时b的值为5
a = a ^ b; // 0001 ^ 0101 ===> 0100,此时a的值为4
System.out.println(“a:”+a); //a:5
System.out.println(“b:”+b); //a:4
}
52、什么是CAS操作?什么ABA问题?如何解决?
CAS全称compare and swap(比较并交换),作用是保证原子性
CAS操作包含三个操作数 —— 内存位置、预期原值、新值。 如果内存位置的值和预期原值相等,就把该值更新为新值,如果不相等,则什么都不做;
ABA问题:CAS操作存在的一个并发问题,打个比方,有两个线程A、B同时操作变量x,A读取到的预期原值是1,此时线程B先将x设置为2,再设置为1,等线程A再来操作的时候,x变量的预期原值和当前值相等,但是x在整个过程中的值是发生过变化的,这在某些业务场景下是不允许的;
解决:利用版本号,给变量x增加版本号,每次操作增加对本版好的判断和修改;
53、什么是回表查询?如何避免?
对于mysql数据库的InnoDB引擎,它的非主键索引是非聚簇索引,索引文件和数据文件分开存储,索引文件B+树的叶节点只保存主键,在进行查询时,需要先去索引文件找到id,再根据id去数据文件查找具体数据,这种现象就叫回表查询
如何避免:索引覆盖
将查询sql中的字段添加到联合索引里面,只要保证查询语句里面的字段都在索引文件中,就无需进行回表查询;
更多索引知识点请移步mysql索引总结
54、什么是CAP理论?
CAP理论是分布式系统架构设计中的一种猜想,或者说是一种理论
- 一致性(Consistence) : 所有节点访问的数据都是一致的;
- 可用性(Availability): 非故障的节点在合理的时间内返回合理的响应(不是错误或者超时的响应);
- 分区容错性(Partition tolerance) : 分布式系统出现网络分区的时候,仍然能够对外提供服务。网络分区指的是网络设备出现的丢包、阻塞、超时等问题。
误区:我发现很多人说到CAP时,都知道分布式系统中这三者不能同时兼顾,只能满足其二,这种说法不严谨,并不是简单的三选二,而是在一致性和可用性二者中只能选其一,分区容错性是我们必须保证的,不能因为出现网络分区导致系统瘫痪,而一致性和可用性可以根据我们的业务来舍弃其一,即我们只能实现AP方案或者CP方案;
55、什么是BASE理论?
BASE理论由CAP理论演化而来,因为CAP对系统设计的要求过高,实现CAP的代价太大;
BASE实质上是对CAP 中 AP 方案的一个补充。
BA:Basically Available(基本可用)
S:Soft-state(软状态) E:Eventually
Consistent(最终一致性)
BASE理论核心思想
牺牲强一致性,通过某些逻辑来达到数据的最终一致性
因为大多数系统对强一致性的依赖没那么强,抛开分区容错性不谈,一致性和可用性这两者,可用性才是我们应该保证的,而对于一致性,我们往往只需要保证最终的数据一致即可;
56、@Autowire和@Resource区别?
都是用来装配java bean
-
@Autowired:按类型注入,这是spring的注解,可以搭配@Qualifie实现按名称注入;
-
@Resource:默认情况下是按照名称进行匹配,如果没有找到相同名称的Bean,则会按照类型进行匹配,这是java自己的注解;
注意事项:
@Autowired有个弊端,打个比方,有个userService,然后它有两个实现类userServiceA和userServiceB,这时候用@Autowired就行不通了,因为它不知道找谁,但是你也不能因为这个一上来就直接用@Resource,这玩意儿性能没@Autowired好,因为@Resource要匹配两次
57、什么是可重入锁?实现原理?
可重入锁:不是一种锁,它是锁的一种性质,代表该锁是否可重入,可重入意思就是**任意线程在获取到锁后能够再次获取该锁,不会被锁阻塞**,这个锁知道它属于谁,其它线程来了就会阻塞等待;
原理:锁的内部维护了线程计数器state和当前持有锁的线程对象,当线程A获取锁资源后,锁会记录下A线程,并且state+1,此时如果有其它线程来获取锁,会被封装成node节点插到队列尾部并且阻塞;而线程A再来获取锁资源时,会成功拿到锁,并且state+1;当线程退出同步代码块时,state-1,如果计数器为0,则释放锁;
58、synchronized可重入吗?ReentrantLock呢?
都是可重入锁,java的锁都可重入
59、RPC协议与HTTP协议的区别?
RPC:远程过程调用,一般用于一台计算机调用另一个计算机上的服务,rpc能让我们像调用本地方法一样调用远程方法;
HTTP:超文本传输协议,一般用于浏览器和服务器之间的通讯;
RPC效率更高,但是实现起来较复杂;
HTTP一般使用json传输数据,RPC一般采用二进制;
60、String有没有长度限制?
既然都这么问了那肯定是有的,分编译器和运行期,长度限制不一样
编译器2 ^ 16 - 1(65535)
运行期2 ^ 32 - 1(2147483647)
不管是编译器还是运行期,如果超出长度都会抛异常:常量字符串过长
61、算法 - 字符串压缩
两种压缩方式
-
只统计字符出现次数,比如aabcccccaaa,压缩成a5b1c5,利用hashMap键的唯一性;
-
统计相邻字符串出现次数,比如aabcccccaaa,压缩成a2b1c5a3,需要维护一个当前对比字符,一个字符出现次数,用第n个字符去和第n+1个字符对比
详细实现demo请移步Java字符串压缩
62、简述一下二叉树,有什么特点,以及它的三种遍历方式
一个递归的树形数据结构,每个节点最多有两个子节点;二叉树一般都是二分查找树,每个节点的值大于它左子节点的值,小于它右子节点的值
递归遍历:
前序遍历:先访问根节点,再访问左子节点,最后访问右子节点
上图中前序遍历结果:30、20、5、28、50、38、58
中序遍历:先访问左子节点,再访问根节点,最后访问右子节点
上图中中序遍历结果:5、20、28、30、38、50、58
后序遍历:先访问左子节点,再访问右子节点,最后访问根节点
上图中后序遍历结果:5、28、20、38、58、50、30
非递归遍历:
常用的是利用栈的先进后出特性,不断地将节点入栈,然后再出栈
非递归前序遍历和非递归中序遍历两种方式很好理解,控制遍历时机即可,而非递归后序遍历较为复杂,需要额外维护一个最后访问节点
专门给对二叉树感兴趣的同学写了个二叉树demo,包含常用方法、遍历方式,注释中有很详细的实现原理,请移步八旬老人彻夜难眠,竟是为了学会二叉树
63、什么websocket?它有什么特点?
作用:
用来和服务端保持长连接,使服务端能主动推送消息给客户端
对比http:
websocket是一种类似http的协议,可以理解成http协议的加强版;http每次请求都需要建立tcp连接,而且一个request只能对应一个response,每次请求必须由客户端发起,由服务端响应;而websocket能使客户端在和服务端建立好tcp连接后,与服务端保持会话连接,服务端可以自由向客户端推送消息;
注意:如果服务端同时维护了很多websocket连接,会对服务端造成很大压力,需要我们对websocket做一些优化(有个互联网独角兽公司面试官这么问我的)
我目前能想到的优化就是:
1、合并推送:将一些能合并的消息整合到一次推送,以此减少websocket连接
2、横向扩展:增加服务器 0.0
64、springboot自动装配原理?
在springboot的启动类上有个SpringBootApplication注解,这是个组合注解,这个注解里面有个注解叫EnableAutoConfiguration注解,@EnableAutoConfigration 注解会导入一个自动配置选择器去扫描每个jar包的META-INF/xxxx.factories 这个文件,这个文件是一个key-value形式的配置文件,里面存放了这个jar包依赖的具体依赖的自动配置类。这些自动配置类又通过@EnableConfigurationProperties 注解支持通过xxxxProperties 读取application.properties/application.yml属性文件中我们配置的值。如果我们没有配置值,就使用默认值,这就是所谓约定大于配置的具体落地点。
65、Eureka和Zookeeper的区别?
都能用来做服务注册与发现,但是两者侧重的点不一样,这跟本文的54点相关,zk是CP架构,而eureka是AP架构
zk集群的master节点挂了以后,会从slave节点中选举一个出来作为master,在选举这段时间内,zk服务不可用,为了保证一致性,牺牲了高可用;
而eureka的节点之间没有主仆关系,当有节点挂了以后,其它节点依然能提供服务,只不过数据可能不一致,为了保证高可用,牺牲了一致性;
66、公平锁和非公平锁的区别?
拿ReentrantLock来说,众所周知,没抢到锁的线程会被放入同步队列,当持有锁的线程释放锁后,此时
公平锁:唤醒第一个没被取消且不为null的节点去拿锁;
非公平锁:所有等待线程都会一起争夺锁,包括队列内和队列外的所有线程;
注意:AQS源码注释中有一句话,大概意思是下个头节点不一定能拿到锁,但那是节点已取消或为null时才会发生,aqs解锁逻辑是依次唤醒后继节点,直到找到第一个没被取消且不为null的节点
一句话总结原理:
AQS维护了一个CLH队列,队列由node节点来实现,试图加锁失败的线程都会进入队列尾部并自旋,当前持有锁的线程释放锁后,AQS会根据公平锁与否唤醒等待线程去抢夺锁
67、mysql如何实现可重复读?
字有点多,但是保证你看完后对可重复读有新的理解
基于mvcc(Multi-Version Concurrency Control,多版本并发控制)
mysql默认隔离级别就是可重复读,这个隔离级别解决了不可重复读和脏读,所谓不可重复读就是在一个事务内多次查询的结果不一样,其原因就是期间数据被另一个事务修改了;脏读就是一个事务读取到了另一个事务未提交的数据,然而该数据回滚了,实际上并未提交;
实现原理前置知识:
InnoDB是通过维护两个隐藏列来实现mvcc,隐藏列记录了数据行创建版本号和删除版本号,每开始一个事务,版本号就会递增;事务开始时刻的版本号就是事务的版本号,用来和查询到的数据行的版本号进行比较;
mvcc在可重复读级别下的具体实现:
查询:需满足两个条件,1、创建版本号小于或等于当前事务版本,这样可以确保查出来的数据都是在本次事务开始前就已经存在,或者由本次事务创建或修改的;2、删除版本号大于当前事务版本号或者未定义(未定义即未删除),这样可以保证在此次事务之前就存在的行没有被删除;
插入:插入的每条数据都需要将创建版本号保存为当前事务版本号;
删除:删除的每条数据都需要将删除版本号保存为当前事务版本号;
修改:插入一条新数据,将创建版本号保存为当前事务版本号,并将原数据的删除版本号保存为当前事务版本号;
68、为什么finally里的代码一定会执行?
编译器在编译的时候,会把finally里面的代码复制多份,分别放在try和catch内所有能够正常执行以及异常执行逻辑的出口处,最直观的就是我们可以在字节码文件里看到很多份finally内部代码;
69、分别说下ConcurrentHashMap1.7和1.8的实现?
1.7
基于Segment数组和HashEntry,Segment继承自ReentrantLock,懂了吧,它自然就有了锁的基本功能;每个Segment数组中都有多个HashEntry,我们的数据都存在HashEntry里面,每次需要修改数据时,先对HashEntry所在的Segment加锁,其它Segment不受影响,分段锁就是这么来的;
1.8
整体实现很像HashMap,在它基础上引入了synchronized,和大量的CAS操作,以及大量的volatile关键字,所以1.8的ConcurrentHashMap中锁的粒度更小;
70、什么是mysql最左匹配原则?
测试数据太多了,直接说结论吧
比如有个表建了a、b、c三个字段的联合索引,那么哪些情况下会触发索引呢
只要查询条件中有a字段就会走索引,不管是bac、cba、ac、ca,都可以走索引,想不到吧,因为mysql有个sql优化器,会自己去优化顺序,但是如果你是bc或者b就不行
技术交流群加v拉:chuanAhaojige8,可以获得内推,技术氛围浓厚,里面个个都是人才,说话又好听
另外
这是本人研发的一款AI工具集,包含智能计算、语言识别、语言加密等实用功能,纯净无广告,希望大家都用一下 ,我劝大家都去用一下,别不识抬举
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V:vip1024b 备注Java获取(资料价值较高,非无偿)
Java高频面试专题合集解析:
当然在这还有更多整理总结的Java进阶学习笔记和面试题未展示,其中囊括了Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构资料和完整的Java架构学习进阶导图!
更多Java架构进阶资料展示
转存中…(img-sPmU9uIS-1711534568158)]
[外链图片转存中…(img-s6fRzgsj-1711534568160)]
[外链图片转存中…(img-brg6xNvF-1711534568160)]
[外链图片转存中…(img-7AIDK0H4-1711534568160)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
[外链图片转存中…(img-CTG2RuAn-1711534568161)]
[外链图片转存中…(img-64zlrHj8-1711534568161)]
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V:vip1024b 备注Java获取(资料价值较高,非无偿)
[外链图片转存中…(img-25cy6Xtt-1711534568162)]
Java高频面试专题合集解析:
[外链图片转存中…(img-1sX16V8M-1711534568162)]
当然在这还有更多整理总结的Java进阶学习笔记和面试题未展示,其中囊括了Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构资料和完整的Java架构学习进阶导图!
[外链图片转存中…(img-Xctt8K8G-1711534568163)]
更多Java架构进阶资料展示
[外链图片转存中…(img-1sFma494-1711534568163)]
[外链图片转存中…(img-H03p7GcH-1711534568163)]
[外链图片转存中…(img-CRikAH5i-1711534568164)]