前言:本文只是记录博主遇到的或者博主认为比较常见的面试题,问题和答案仅代表博主个人观点。如果正在看这篇博文的你有你认为比较常见而我没有记录的,欢迎评论,我会挑选记录,方便大家一起面试造火箭。(不定时更新)
1.HashMap的底层原理
HashMap可以接受null的键值对,是线程不安全的,它是基于hashing的原理,jdk8后采用数组+链表+红黑树的数据结构。通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。当两个不同的键对象的hashcode相同时,它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。
2.Redis持久化的几种方式
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。过程比较简单,也不需要过多配置。
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。可以说几乎是用户的每一个操作,都会记录。RDB比AOF恢复数据较快,性能较高,但是数据安全性较低。
3.悲观锁与乐观锁
悲观锁总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁,用于多写的情况;乐观锁总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。用于多读的情况。
4.数据库数据太多跑不动怎么办
垂直分库和垂直分表
垂直分库就是根据业务耦合性,将关联度低的不同表存储在不同的数据库。
垂直分表就是把一些字段长度大的单独出来用一个字段关联
水平切分 库内分表(比如按月份数据分表) 分库分表(先按业务分库,再按月份分表)
5.#与$的区别
#会对SQL进行预编译,一般传字段参数值使用,如id = #{id},$不会进行预编译,传进来是什么就是什么,一般用于传表名或者字段,如 order by ${id},但需要注意防SQL注入,比如传表名的时候传入user;--则会导致后面的SQL被注释掉从而导致SQL注入问题,一般能用#尽量用#,如果使用$要对传入值进行判断。
6.String与StringBuffer与StringBuilder的区别
String是不可变的,每次对String的操作都会生成新的String对象,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象;StringBuffer是线程安全的,效率较低,StringBuilder是线程不安全的,效率较高;效率StringBuilder > StringBuffer > String,如果要操作少量的数据用String,单线程操作字符串缓冲区下操作大量数据用StringBuilder,多线程操作字符串缓冲区下操作大量数据 用StringBuffer
7.spring的IOC和AOP底层原理
IOC为控制反转,将创建对象交给spring去做,spring通过扫描注解,或者解析xml配置文件,获取class的属性值,然后通过反射创建对象保存在IOC容器中。
AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类。JDK 动态代理机制只能对接口进行代理,其原理是动态生成一个代理类,这个代理类实现了目标对象的接口,目标对象和代理类都实现了接口。CGLIB 是对目标对象本身进行代理,其原理是使用字节码生成工具在内存生成一个继承目标对象的代理类,然后创建代理对象实例。
8.简单说说集合
集合主要分为List,Set,Map,其中List和Set继承Collection接口;
List主要分为ArrayList,Vector,LinkedList,
ArrayList的底层数据结构是数组,查询快,增删慢,线程不安全,效率高
Vector的底层数据结构是数组,查询快,增删慢,线程安全,效率低
LinkedList的底层数据结构是链表,查询慢,增删快,线程不安全,效率高
需要线程安全使用Vector,查询较多使用ArrayList,增删较多使用LinkedList
Set主要分为HashSet,LinkedHashSet,TreeSet
HashSet底层数据结构是Hash表,无序且唯一,通过hashCode()和equals()方法保证数据的唯一性。
LinkedHashSet的底层数据结构是链表和哈希表,有序且唯一,通过链表保证元素有序,通过哈希表保证数据唯一。
TreeSet底层数据结构是红黑树,有序且唯一,通过自然排序或者比较器排序保证元素排序,根据比较的返回值是否是0来决定保证数据唯一。
需要排序则使用TreeSet,需要有序则使用LinkedHashSet,不需要排序则使用HashSet
Map主要分为HashMap,TreeMap,HashTable,ConcurrentHashMap
HashMap存储数据采用的哈希表结构,无序,线程不安全,效率高,key和value都允许有空值null。
HashTable是线程安全的,效率低,所有public方法声明中都有synchronized关键字,不允许有空值null。