Java面试问题总结
2020-06-18 18:24:16 0 举报
AI智能生成
登录查看完整内容
为你推荐
查看更多
Java面试宝典
作者其他创作
大纲/内容
Java面试问题总结
常用框架
spring
aop
ioc
概念:IoC,控制反转,又叫依赖注入。即将代码里对象之间的依赖关系转移到容器中,这样就能够很灵活地通过面向接口的编程方式改变真正的实现类
概念补充:Spring的IoC容器是ApplicationContext
常用的ApplicationContext
ClassPathXmlApplicationContext:从ClassPath路径中加载XML配置的上下文
FileSystemXmlApplicationContext:从文件系统中加载XML配置的上下文
XmlWebApplicationContext:Web开发中从xml中加载Web上下文,区别与上面两个之处在于,此上下文是基于ServletCotext的
AnnotationConfigWebApplicationContext:从注解类中加载Web上下文
MyBatis
缓存
一级缓存:Mybatis默认开启一级缓存,其是SqlSession级别的,Session结束缓存即清空
二级缓存:MyBatis的二级缓存是Mapper级别的,需要手动开启
SpringBoot
SpringCloud
注册中心
概述:在微服务架构中,注册中心是核心的基础服务之一。注册中心可以说是微服务架构中的”通讯录“,它记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到这里,当服务需要调用其它服务时,就到这里找到服务的地址,进行调用。
CAP理论
概述:CAP理论是分布式架构中重要理论
一致性(Consistency):所有节点在同一时间具有相同的数据
可用性(Availability): 在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求
分区容忍性(Partition tolerance):分区容错性指在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。
PS:CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。
Apache Zookeeper(CP)
概述:Apache Zookeeper 在设计时就紧遵CP原则,即任何时候对 Zookeeper 的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性,但是 Zookeeper 不能保证每次服务请求都是可达的。
集群单点问题处理:当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30~120s,而且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。
补充说明:从 Zookeeper 的实际应用情况来看,在使用 Zookeeper 获取服务列表时,如果此时的 Zookeeper 集群中的 Leader 宕机了,该集群就要进行 Leader 的选举,又或者 Zookeeper 集群中半数以上服务器节点不可用(半数以上存活,集群方可使用),那么将无法处理该请求。所以说,Zookeeper 不能保证服务可用性。
Spring Cloud Eureka(AP)
概述:Spring Cloud Netflix 在设计 Eureka 时就紧遵AP原则(尽管现在2.0发布了,但是由于其闭源的原因 ,但是目前 Ereka 1.x 任然是比较活跃的)。
集群单点问题处理:Eureka Server 也可以运行多个实例来构建集群,解决单点问题,但不同于 ZooKeeper 的选举 leader 的过程,Eureka Server 采用的是Peer to Peer 对等通信。这是一种去中心化的架构,无 master/slave 之分,每一个 Peer 都是对等的。在这种架构风格中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。每个节点都可被视为其他节点的副本。
补充说明:Eureka的集群中,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障。此时会出现以下几种情况
1、Eureka不再从注册表中移除因为长时间没有收到心跳而过期的服务
2、Eureka仍然能够接受新服务注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用);
3、当网络稳定时,当前实例新注册的信息会被同步到其它节点中;
Consul(CP)
概述:Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。Consul 使用 Go 语言编写,因此具有天然可移植性(支持Linux、windows和Mac OS X)。Consul 遵循CAP原理中的CP原则,保证了强一致性和分区容错性,且使用的是Raft算法,比zookeeper使用的Paxos算法更加简单。
集群单点问题处理:服务注册的时间会稍长一些,因为 Consul 的 raft 协议要求必须过半数的节点都写入成功才认为注册成功 ;在leader挂掉了之后,重新选举出leader之前会导致Consul 服务不可用。
Consul强一致性(C)带来的是:服务注册相比Eureka会稍慢一些。因为Consul的raft协议要求必须过半数的节点都写入成功才认为注册成功 Leader挂掉时,重新选举期间整个consul不可用。保证了强一致性但牺牲了可用性。
Nacos
概述:Nacos是阿里开源的,Nacos 支持基于 DNS 和基于 RPC 的服务发现。在Spring Cloud中使用Nacos,只需要先下载 Nacos 并启动 Nacos server,Nacos只需要简单的配置就可以完成服务的注册发现。
补充说明:Nacos除了服务的注册发现之外,还支持动态配置服务。动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。
总结:一句话概括就是Nacos = Spring Cloud注册中心 + Spring Cloud配置中心。
常见协议
Http
Coap
数据库
MySQL
SQL基础
连接查询
inner join(内连接)
概述:在两张表进行连接查询时,只保留两张表中完全匹配的结果集。
left join(左连接)
概述:在两张表进行连接查询时,会返回左表所有的行,即使在右表中没有匹配的记录。
right join(右连接)
概述:在两张表进行连接查询时,会返回右表所有的行,即使在左表中没有匹配的记录。
full join(全连接)
概述:在两张表进行连接查询时,返回左表和右表中所有没有匹配的行。
PS:查询结果是left join和right join的并集
union与union all的区别
UNION
概述:将两个结果集合并为一个
对重复结果的处理:会筛选掉重复的记录
对排序的处理:Union将会按照字段的顺序进行排序
UNION ALL
概述:将两个结果集合并为一个(不会去除重复记录)
对重复结果的处理:不会去除重复记录
对排序的处理:UNION ALL只是简单的将两个结果合并后就返回
从效率上说,UNION ALL 要比UNION快很多,所以,如果可以确认合并的两个结果集中不包含重复数据且不需要排序时的话,那么建议用UNION ALL
SQL优化
Redis
概述:Redis是基于内存的存储的非关系型数据库,它可以存储键值对数据
支持的数据结构类型
STRING(字符串)
常用指令
SET
概述:设置存储在给定键中的值
eg:set hello word
GET
概述:获取存储在给定键中的值
eg:get hello
DEL
概述:删除存储在给定键中的值(该命令可以用于所有类型)
eg:del hello
LIST(列表)
ZSET(有序集合)
SET(集合)
HASH(散列)
数据持久化
快照
概述:通过创建快照的方式来获取存储在内存里面的数据在某个时间点上的副本
适用场景:即使丢失一部分数据也不会造成问题的应用程序
AOF
概述:AOF持久化会将被执行的写命令写到AOF文件的末尾,以此来执行数据发生的变化。因此Redis只要从头到尾重新执行一次AOF文件包含所有的写命令,就可以恢复AOF文件所记录的数据集
适用场景:所有数据都比较重要的应用程序
开启方式:通过appendonly yes配置选项打开
appendfsync选项及其同步频率
always:每个Redis写命令都要同步写入硬盘,这样做会严重降低Redis的速度
everysec:每秒执行一次同步,显示地将多个写命令同步到硬盘上
no:让操作系统来决定应该如何进行同步
mongo
Java基础
集合
List
ArrayList
Set
Map
HashMap(待进一步完善)
概述:它根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用ConcurrentHashMap
存储结构:HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,链表长度大于8时转换为红黑树
关键字段概述
final int hash(用来定位数组索引位置)
final K key
V value
int threshold
概述:下次要调整的大小值(capacity * load factor)
final float loadFactor
概述:哈希表的负载因子
负载因子值确定:默认的负载因子0.75是对空间和时间效率的一个平衡选择,建议大家不要修改,除非在时间和空间比较特殊的情况下,如果内存空间很多而又对时间效率要求很高,可以降低负载因子Load factor的值;相反,如果内存空间紧张而对时间效率要求不高,可以增加负载因子loadFactor的值,这个值可以大于1。
transient int modCount
概述:对该HashMap进行结构修改的次数结构修改是指更改HashMap中的映射次数或以其他方式修改其内部结构(例如:重新哈希)的次数。此字段用于使HashMap的Collection-view上的迭代器快速失败。 (请参见ConcurrentModificationException)
transient int size
概述:此映射中包含的键-值对数
高频面试问题
1、HashMap就是使用哈希表来存储的,针对于哈希表出现的冲突,有哪些解决方法,并说明每种方法的优缺点,Java中是采用哪种方法解决哈希表冲突的
解决冲突的两种方式
开放地址法
原理:当发生地址冲突时,按照某种方法继续探测哈希表中的其他存储单元,直到找到空位置为止。
优缺点:容易产生堆积问题;不适于大规模的数据存储;散列函数的设计对冲突会有很大的影响;插入时可能会出现多次冲突的现象,删除的元素是多个冲突元素中的一个,需要对后面的元素作处理,实现较复杂;结点规模很大时会浪费很多空间;
链地址法
优缺点:处理冲突简单,且无堆积现象,平均查找长度短;链表中的结点是动态申请的,适合构造表不能确定长度的情况;相对而言,拉链法的指针域可以忽略不计,因此较开放地址法更加节省空间。插入结点应该在链首,删除结点比较方便,只需调整指针而不需要对其他冲突元素作调整。
Java中HashMap采用了链地址法。
ConcurrentHashMap
Hashtable
概述:Hashtable是遗留类,很多映射的常用功能与HashMap类似,不同的是它承自Dictionary类,并且是线程安全的,任一时间只有一个线程能写Hashtable,并发性不如ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。Hashtable不建议在新代码中使用,不需要线程安全的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换。
LinkedHashMap
概述:LinkedHashMap是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的,也可以在构造时带参数,按照访问次序排序。
TreeMap
概述:TreeMap实现SortedMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。
JVM
Java内存模型
Java虚拟机类加载过程
1、加载
2、验证
3、准备
5、初始化
Java对象创建过程
1⃣️类加载检查
概述:虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过,如果没有,那必须先执行相应的类加载过程
2⃣️分配内存
概述:在类加载检查通过后,接下来虚拟机就会为新生对象分配内存,对象所需内存的大小在类加载完成后便可确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来
内存分配的两种方式
备注:选择哪种分配内存的方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定
指针碰撞
适用场景:堆内存规整的情况下(即没有内存碎片)
原理:所用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配的内存就仅仅是把那个指针向空闲空间那边移动一段与对象大小相等的距离
GC收集器:Serial、ParNew
空闲列表
适用场景:堆内存不规整的情况下
原理:虚拟机会维护一个列表,记录上哪些内存块是可用的,在分配内存的时候从列表中找到一块足够大的空间划分给对象实例
GC收集器:CMS
多线程
线程生命周期
新建:就是刚使用new方法,new出来的线程;
就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;
运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;
阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态;
销毁:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源;
线程创建方式
实现Runnable接口的run方法
继承Thread类并重写run方法
使用FutureTask方式
三种方式对比:实现Runnable接口好处是Java支持多实现;继承Thread类好处是方便传参;使用FutureTask方式可以得到任务的返回
线程池的最佳线程数量计算
IO密集型应用
概念:IO密集型指的是系统的CPU性能相对硬盘、内存要好很多,此时,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高。
简述:需要大量的IO操作
线程数计算规则:2N+1
CPU密集型应用
概念:CPU密集型也叫计算密集型,指的是系统的硬盘、内存性能相对CPU要好很多,此时,系统运作大部分的状况是CPU Loading 100%,CPU要读/写I/O(硬盘/内存),I/O在很短的时间就可以完成,而CPU还有许多运算要处理,CPU Loading很高。
简述:一般进行大数据运算,cpu消耗较大
线程数计算规则:N+1
备注:上述N代表CPU核数
收藏
0 条评论
回复 删除
下一页