8.数字马力他人面试题
8.1Java基础
8.1.1 HashMap的put元素步骤
- 计算键的哈希值
- 检查容量并可能扩容
- 处理哈希冲突(链地址法或红黑树)
- 替换或谈价键值对
- 再次检查扩容
8.2 计算机网络
8.2.1 OSI哪些层,每层作用以及有哪些协议
- 物理层:在通信媒体上传输原始比特流
- 数据链路层:提供单个链路的点到点数据传输,包括错误检测和纠正;协议PPP
- 网络层:负责源主机和目标主机选择合适路径,将数据包从一个网络转发到另一个网络;协议:IP、ICMP、IGMP
- 传输层:提供端到端可靠或不可靠的数据传输,包括错误恢复,流量控制;协议TCP、UDP
- 会话层:管理会话的建立、维护和节数,同步对话,控制会话数据的交换;协议:RPC
- 表示层:处理数据的表现形式,数据加密、解密、压缩、解压缩以及数据格式转换
- 应用层:为用户提供网络服务接口,文件传输;协议:HTTP、FTP、SMTP、DNS、TLS/SSL
8.2.2 TCP如何保证可靠传输
- 确认应答机制:每当发送方发送一个数据包都会附带一个序列号,接收方收到数据后,会发送一个带有确认序列号的ACK报文给发送方,表示特定序列号的数据已收到。如果发送方没有收到对应的ACK,就会重传数据包。
- 超时重传(根据RTT(数据发送到接收确认)设置RTO(略大于RTT)):发送方在发送数据包时会设置一个计时器,如果在预期时间内未收到该数据包的ACK,就会重新发送数据包。在数据包丢失或确认应答丢失时重传。
- 流量控制:通过滑动窗口(发送方:已发送已确认、已发送、未确认、未发送接收范围内,未发送接收范围内;接收方:已接收确认、未接收可接受、未接收不可接受)控制数据发送效率,防止发送方过快发送数据导致接收方无法处理,从而避免数据丢失。接收方会告诉发送方接收缓冲区可用空间大小。
- 拥塞控制:通过慢启动(接收一个ACK,拥塞窗口+1,成倍增)、拥塞避免(收到一个ACK,拥塞窗口+1/拥塞窗口,线性增长)、拥塞发生(快速重传(以数据驱动重传,三次相同ACK应答)、窗口阈值设为原来的1/2,拥塞窗口重置为1)、快速恢复(拥塞窗口设为原来一半,阈值为拥塞窗口数),等算法动态调整数据的发送效率、以应对网络拥塞情况,避免过多的数据包在网络中造成丢包
- 数据校验:TCP头部包含一个校验和字段用于检测数据再传输过程中是否损坏。
8.3 Spring相关
8.3.1 Bean的生命周期
- 实例化:spring容器通过读取配置元数据(XML文件、注解、Java配置类)来创建Bean实例。通过反射调用Bean类的默认构造方法或静态工厂或实例工厂实例化Bean。
- 属性赋值:实例化后,Spring容器通过DI为Bean设置属性。包括填充其他Bean引用和基本类型值,依据配置元数据。
- Aware接口注入(如有必要):如果Bean实现了Spring提供的Aware接口(BeanNameAware、ApplicationContextAware),Spring容器会调用相应的setXXX方法,将相关的上下文信息注入到Bean中,让Bean知道自己的名字或拥有ApplicationContext的引用。
- 初始化前处理(BeanPostProcessor前置处理):如果有BeanPostProcessor存在并且需要在Bean初始化之前进行某些处理(比如代理的创建),此时这些后处理器的
postProcessBeforeInitialization
方法会被调用 - 初始化:Spring容器会调用Bean定义的指定的初始化方法。在配置中声明init-method或在Bean类中使用@PostConstract注解实现。此阶段Bean完成所有必要设置,准备就绪供应用程序使用。
- 使用:Bean处于活动状态,可被应用程序中其他组件使用。
- 初始化后处理(BeanPostProcessor):初始化完成后,如果有BeanPostProcessor,其
postProcessAfterInitialization
方法会被调用,允许进一步自定义处理或修改Bean。 - 销毁前处理(可选):当Spring容器关闭或Bean不再需要时,如果Bean实现了
DisposableBean
接口或使用了@PreDestroy
注解指定了销毁方法,Spring会调用这些方法进行资源清理。 - 销毁:Spring容器负责调用销毁方法来清理资源,释放Bean所占用的内存,完成整个生命周期
8.3.2 怎么解决循环依赖
- 一级缓存(singletonObjects):存放完全初始化的单例Bean实例。
- 二级缓存(earlySingletonObjects):存放提前曝光的Bean实例,即已完成实例化但尚未完成属性填充和初始化方法调用的单例Bean。
- 三级缓存(singletonFactories):存放用于创建Bean实例的工厂对象,这些工厂对象可以用来产生早期的Bean实例引用。
具体流程:
- 初始化A,发现A依赖于B;
- 暂停A尝试获取B(A早期实例未完成属性设置和初始化被包装成一个ObjectFactotiry放入三级缓存的singletonFactories中);
- Bean初始化,B依赖于A,B能够从三级缓存中找到A,完成B的初始化;
- 然后返回处理A(可获取初始化后的B);
- 清理缓存。
8.4 Redis
8.4.1 Redis常用命令
键(Key)命令
DEL key [key ...]
:删除一个或多个键。EXISTS key
:检查给定的键是否存在。TYPE key
:返回键的类型。EXPIRE key seconds
:为键设置过期时间(单位秒)。TTL key
:获取键的剩余过期时间(单位秒)。
字符串(String)命令
SET key value
:设置键的值。GET key
:获取键的值。INCR key
:递增键的整数值。DECR key
:递减键的整数值。APPEND key value
:在键的值后面追加字符串。
哈希(Hash)命令
HSET key field value
:设置哈希表中字段的值。HGET key field
:获取哈希表中字段的值。HGETALL key
:获取哈希表中所有字段和值。HDEL key field [field ...]
:删除哈希表中一个或多个字段。
8.5 Git
8.5.1 Git常用命令
- 初始化仓库:git init
- 配置 git config
- 克隆:git clone
- 添加文件:git add .(所有修改文件)
- 提交:git commit
- 查看状态:git status
- 查看差异:git diff
- 分支操作:git brach(列出所有分支),git merge(合并指定分支到当前分支)
- 查看分支:git log
- 推送和拉取:git push\pull
8.5.2 代码冲突如何解决
- 识别冲突:通过git status查看哪些文件冲突
- 打开冲突文件:
- 手动解决冲突:选择或合并大妈
- 标记冲突已解决
- 提交解决冲突
- 继续合并或推送
8.6 设计模式
8.6.1 单例模式中的懒汉模式不加volatile关键字会怎么样?
-
指令重排序:在没有
volatile
关键字的情况下,编译器和处理器为了优化性能,可能会对代码执行顺序进行重排序。这意味着,即使你使用了双检锁(Double-Checked Locking,DCL)模式,实例化对象和赋值给静态变量的指令顺序可能并不会严格按照代码书写的顺序执行。这可能导致其他线程在实例未完全构造完成时就看到该实例,从而引发空指针异常或其他并发问题。 -
可见性问题:当一个线程在初始化单例实例后,如果没有
volatile
关键字,其他线程可能无法立即看到这个变化,因为volatile
关键字会确保对它的修改立即对其他线程可见,而不仅仅是存储在各自的线程缓存中。这可能导致其他线程看到的是过时的实例引用,也就是未初始化的实例引用。
8.6.3 工厂模式
简单工厂
简单工厂模式又称静态工厂方法模式,它有一个专门的工厂类,根据传入的参数决定创建何种产品类的实例。这种模式中,客户端不需要知道具体产品的类名,只需知道所对应的参数即可。
实现方式:
- 定义一个抽象产品类(Product),声明一些公共接口。
- 定义多个具体产品类(ConcreteProductA, ConcreteProductB),实现抽象产品类的接口。
- 创建一个工厂类(Factory),工厂类中包含一个静态方法,根据传入的参数(如字符串或枚举类型),返回具体产品的实例。
工厂方法
工厂方法模式定义了一个用于创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
实现方式:
- 定义一个抽象工厂接口(Creator),声明一个创建产品的抽象方法。
- 定义多个具体工厂类(ConcreteCreatorA, ConcreteCreatorB),每个工厂类都实现了抽象工厂接口中的方法,用于创建对应的具体产品。
- 定义抽象产品类(Product)和具体产品类(ConcreteProductA, ConcreteProductB),具体产品类实现抽象产品接口。
抽象工厂
抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。
实现方式:
- 定义一个抽象工厂接口(AbstractFactory),声明多个创建产品的方法,每个方法对应一种产品。
- 定义多个具体工厂类(ConcreteFactory1, ConcreteFactory2),实现抽象工厂接口,提供具体产品的创建方法。
- 定义多个产品接口(ProductA, ProductB)及其实现类(ConcreteProductA1, ConcreteProductA2, ConcreteProductB1, ConcreteProductB2),每个具体工厂负责创建一系列相关的产品。