基于尚硅谷的面试总结
1. 单例模式
单例模式有【饿汉式】和【懒汉式】之分。饿汉式是在类加载的时候就进行对象的创建,而懒汉式是在需要使用的时候进行对象的创建
创建饿汉式的三种方式
饿汉式 1.直接创建 2.枚举 3. 静态代码块
【 可以避免线程安全问题 】
* 构造器私有化
* 自行创建,并且用静态变量保存
*
* final 修饰类中的属性
* 表示该属性一旦被初始化便不可改变,这里不可改变的意思对基本类型来说是其值不可变,而对对象属性来说其引用不可再变。
*/
// 1.
public class ESingleton {
public static final ESingleton ENSTANCE = new ESingleton();
private ESingleton(){}
}
// 2.
// 枚举类的构造器都是私有的
public enum ESingletonEnum {
INSTANCE
}
//3.
public static final ESingletonStaticBlock INSTANCE;
static{
INSTANCE = new ESingletonStaticBlock();
}
private ESingletonStaticBlock (){}
注意: 对于饿汉式枚举方式最简单
创建懒汉式的三种方式
/* 懒汉式
* 构造器私有化
* 在类中使用静态变量保存唯一的使用
* 懒汉式可能会发生【线程安全】的问题
*/
// 1.
public class LazySingleton {
// 这里使用private而不使用public因为不能通过调用这个属性而创建对象
// 这样创建出来的对象为空 【null】
private static LazySingleton LAZYSINGLETON ;
private LazySingleton(){}
public static LazySingleton getInstance(){
if (LAZYSINGLETON == null) {
LAZYSINGLETON = new LazySingleton();
}
return LAZYSINGLETON;
}
}
// 2.
public class LazySingletonBySuo {
private static LazySingletonBySuo LAZYSINGLETON ;
private LazySingletonBySuo(){}
public static LazySingletonBySuo getInstance(){
if (LAZYSINGLETON == null) { //为了性能考虑
synchronized (LazySingletonBySuo.class){ //为了安全考虑
if (LAZYSINGLETON == null) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LAZYSINGLETON = new LazySingletonBySuo();
}
}
}
return LAZYSINGLETON;
}
}
// 测试
//以下测试的是懒汉式
// 先保证线程安全 加锁
new Thread() {
@Override
public void run() {
LazySingletonBySuo lazySingleton = LazySingletonBySuo.getInstance();
System.out.println(Thread.currentThread().getName()+lazySingleton);
}
}.start();
new Thread() {
@Override
public void run() {
LazySingletonBySuo lazySingleton = LazySingletonBySuo.getInstance();
System.out.println(Thread.currentThread().getName()+lazySingleton);
}
}.start();
// 运行结果
// Thread-0singleton.LazySingletonBySuo@2a75ae17
// Thread-1singleton.LazySingletonBySuo@2a75ae17
//但是呢,如果在方法中调用了线程睡眠1秒,这个时候就会发生【不是单例的情况】
//Thread-1singleton.LazySingletonBySuo@5a2cdcfd
//Thread-0singleton.LazySingletonBySuo@3ca00ad1
//出现这种的情况就是 第一个线程判断出了为空,然后阻塞
//让出cpu使第二个线程使用
//第二个线程进入这个方法,也判断出为空,阻塞
//在往后继续执行的时候,都创建了对象、
// 解决办法 加锁synchronized
// 优化,在加锁之前判断是否为空,如果为空,就去创建,否则,返回
}
// 3.
// 内部类不会随着外部类的加载而创建,只有使用的时候,才会创建
public class LazySingletonYouHua {
private LazySingletonYouHua(){}
private static class Inner{
private static LazySingletonYouHua LAZYSINGLETON = new LazySingletonYouHua();
}
public static LazySingletonYouHua getInstance(){
return Inner.LAZYSINGLETON;
}
}
在懒汉式中,使用内部类最方便
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
2.类的初始化和实例的初始化
自己算算答案是什么
答案是:
解析:
/*
想创建实例就要先加载类并进行初始化
* main方法所对应的类先进行加载并初始化 (static修饰的在类加载的时候就执行了)
*
* 类加载并初始化:
* 先父类后子类,加载【静态变量赋值代码】和【静态代码块】(这两个根据代码顺序执行)
* 实例加载并初始化:
* 1. super() 这里的执行也是 1,2,3的执行顺序
* 2. 【非静态变量赋值代码】和【非静态代码块】 (这两个根据代码顺序执行) 3.构造方法
*
* 方法重写:
* 由于多态,所以出现了父类上的执行结果是子类的执行结果
* 什么不能出现方法重写呢? 【1】 final修饰 【2】 static修饰 【3】private子类不可见的
*/
3.方法的参数传递机制
- 基本数据类型,传递的是值
- 引用数据类型,传递的是地址
例题:
注意: 全局变量引用在栈中,其值在堆中;方法的执行在栈中
4.全局变量和局部变量
public class TestVariable{
int i;
int j;
{
int i = 10;
i++;
j++;
}
public int test(int j){
j++;
i++;
return j;
}
public static void main(String[] args) {
TestVariable test1 = new TestVariable();
TestVariable test2 = new TestVariable();
test1.test(10);
test1.test(20);
test2.test(30);
System.out.println(test1.i+","+test1.j); // 2,1
System.out.println(test2.i+","+test2.j); // 1,1
}
}
5 ssm的面试题
1)Spring Bean的作用域有什么区别
在Spring中,可以在 元素的scope属性里设置bean的作用域,以决定这个bean是单实例还是多实例的。默认情况下是单实例。
类别 | 说明 |
---|---|
singleton | 在SpringIOC容器中仅存在一个Bean实例,当IOC容器一创建就会创建Bean的实例,Bean以单实例的方式存在 |
prototype | 每次调用getBean()时都会返回一个新的实例 |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session共享一个Bean,不同的HTTP使用不同的Bean。该作用域仅适合于WebApplicationContext环境 |
2)Spring支持的常用的数据库事务传播属性和设置事务的隔离级别
事务的属性:
1. propagation : 设置事务的传播行为
传播行为: 一个方法运行在了一个开启事务的方法中时,当前方法是使用原来的事务还是开启一个新的事务
- Propagation.REQUIRED: 默认值,使用原来的事务
- Propagation.REQUIRES_NEW : 将原来的事务挂起,开启一个新的事务
2.isolation : 设置事务的隔离级别
-Isolation.REPEATABLE_READ :可重复读,MySQL默认的隔离级别
-Isolation.READ_COMMITED: 读已提交,Oracle默认的隔离级别,开发时通常使用的隔离级别
事务的隔离级别讲的比较好的一篇文章:
https://developer.aliyun.com/article/743691
3)springMVC的工作流程
- 这篇文章比较好: https://www.jianshu.com/p/4851dbedb63d
需要注意的就是Handler和HandlerMapping和HandlerRequest的区别
4)mybatis当实体类中的属性名和表中的字段不一致时的解决办法
方法一: 写SQL语句时起别名
select create_time createTime from xxxxx;
方法二:开启驼峰命名规则
在mybatis配置文件中
<setting name=”mapUnderscoreToCamelCase” value=”true”/>
在springboot的yml文件中
mybatis.configuration.map-underscore-to-camel-case:=true
方法三:在mapper映射文件中使用resultMap自定义规则
<resultMap type=”” id=””>
<result column=”create_time”
property=”createTime”/>
</resultMap>
方法四: 编写Mybatis配置类
@Configuration
public class MyBatisConfig {
@Bean
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer() {
@Override
public void customize(Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}
6 mysql什么时候建立索引
索引是 【数据结构】,检索查询数据时快,排序快。但是做一些写操作比较慢了,并且占空间
以下情况需要建立索引
- 主键自动建立唯一索引
- 频繁作为查询条件的字段应该创建索引
- 查询中与其他表关联的字段,外键关系建立索引
- 单键/组合索引的选择问题,组合索引性价比更高
- 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
- 查询中统计或者分组字段
以下情况不需要建立索引
- 表记录太少
- 经常增删改的表或者字段
- where条件里用不到的字段不创建索引
- 过滤性不好的不适合建立索引
7.Redis在项目中的使用场景
数据类型 | 使用场景 |
---|---|
String | 什么时候封锁一个IP地址 使用 incrby命令 |
Hash | 存储用户信息【id,name,age】这种的不建议使用string类型来存储,因为它会将所有的都序列化 |
Lsit | 实现最新消息的【排行】,还可以利用List的push命令,将任务存在list集合中 Redis–list数据类型来模拟消息队列【电商中的秒杀就可以采用这种方法来完成一个秒杀活动】 |
Set | 可以自动排重 微博中将每个人的好友存在Set中 |
Zset | SortedSet 【以某个条件为权重进行排序】 例如:商品详情的时候,都会有一个排名,还可按照价格进行排名 |
8.购物车实现过程
购物车:
1. 购物车和用户的关系
1) **一对一**,一个用户对应一个购物车
2) 单点登录一定在购物车之前
2. 跟购物车有关的操作有哪些
1)添加购物车
a)用户未登录状态下的添加
i: 添加到什么地方
ii: 未登录将数据保存到什么地方 Redis Cookie(自己开发项目时)
b) 用户已登录状态下的添加
i: 添加到Redis缓存中,为了读取速度快。用Hash来存储hset(key,field,value)
ii:存在数据库中,保证数据的安全性
2)展示购物车
a)未登录状态
直接从cookie中取得数据展示数据即可
b)登录转态
用户一旦登录:必须显示数据库【Redis】+cookie中的数据
9.消息队列在项目中的使用
背景: 在分布式系统中是如何处理高并发的
由于在高并发的环境下,来不及同步处理用户发送的请求,则会导致请求发生阻塞。
比如:大量的insert,update之类的请求同时到达MYSQL,直接导致无数的行锁表锁,甚至会导致请求堆积很多,从而触发 too many connections错误。
使用消息队列可以解决【异步通信】
同步/异步 阻塞/非阻塞的区别
-
同步/异步 关注的是消息通知的机制
-
阻塞/非阻塞 关注的是等待消息中的机制
看图:
// ===== == 或者===============
并行
排队
消息队列在电商使用场景
消息队列的弊端: 发送消息的不确定性【延迟队列和轮询技术来解决】