八股Ⅰ
自增变量
-
自增自减都是直接修改变量的值,不经过操作数栈
执行 i = i++; 先将i变量压入操作数栈,然再对i变量进行自增,最后把计算结果赋值给 i , i 仍然是1
什么是Singlenton?
单实例设计模式,即某个类在整个系统中只能有一个实例对象可获取和使用的代码模式
要点:
-
某个类只有一个实例:构造器私有化
-
自行创建实例,并使用静态变量保存这个唯一实例
-
向外提供这个实例:直接暴露、用静态变量的get方法获取
-
强调这是一个单例,可以用final修饰
常见形式:
-
饿汉式:直接创建对象,不存在线程安全问题
//直接实例化
public class Singleton1 {
private Singleton1() {
}
public static final Singleton1 INSTANCE = new Singleton1();
}
//枚举式 JDK1.8之后
public enum Singleton2 {
INSTANCE
}
//静态代码块
public class Singleton3 {
public static final Singleton3 INSTANCE;
private String info;
static {
try {
INSTANCE = new Singleton3("123");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private Singleton3(String info) {
this.info = info;
}
} -
懒汉式:延迟创建对象
//线程不安全
public class Singleton4 {
static Singleton4 instance;
private Singleton4() {}
public static Singleton4 getInstance() {
if (instance == null) {
instance = new Singleton4();
}
return instance;
}
}
//线程安全
public class Singleton5 {
static Singleton5 instance;
private Singleton5() {}
public static Singleton5 getInstance() {
if (instance == null) {
synchronized (Singleton5.class) {
if (instance == null) {
instance = new Singleton5();
}
return instance;
}
}
return instance;
}
}
//静态内部类
public class Singleton6 {
/**
* 1、内部类被加载和初始化时,才创建INSTANCE实例对象
* 2、静态内部类不会自动创建,随着外部类的加载初始化而初始化,他是要单独去加载和实例化的
* 3、因为是在内部类加载和初始化时,创建的,因此线程安全
*/
private Singleton6(){}
public static class Inner{
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance() {
return Inner.INSTANCE;
}
}
类初始化实例初始化
类初始化:
-
一个类要创建实例需要先加载并初始化该类
-
main方法所在的类需要先加载和初始化
-
一个子类要初始化需要先初始化父类
-
一个类初始化就是执行 clinit 方法
-
clinit 方法由静态变量显示赋值代码和静态代码块组成
-
类变量显示赋值代码和静态代码块代码从上到下执行
-
clinit 方法只调用一次
实例初始化过程:
-
实例初始化就是执行 init() 方法
-
init () 方法可能重载有多个,有几个构造器就有几个 init() 方法
-
init() 方法由非静态实例变量显示赋值代码和非静态代码块,对应构造器代码组成
-
非静态实例变量显示赋值代码和非静态代码块从上到下顺序执行,而对应构造器的代码最后执行
-
每次创建实例对象,调用对应构造器,执行的就是对应的 init 方法
-
init 方法的首行是super()和super(实参列表) ,即对应父类的 init 方法
哪些方法不能重写Override:final修饰、静态方法、private等子类不可见方法
多态性:子类重写了父类的方法,通过子类对象调用的是子类的方法;非静态方法默认的调用对象时this;
方法参数传递机制
1、形参是基本数据类型
-
传递数值
2、实参是引用数据类型
-
传递地址值
特殊的类型:String、包装类等对象的不可变性
递归与迭代
递归:
-
大问题化为小问题,可以较少代码量,可读性好;
-
递归调用浪费空间,递归太深容易堆栈溢出
迭代:
-
代码运行效率好,时间只随迭代次数增加而增加,没有额外的空间开销
-
代码不简洁,可读性差
成员变量与局部变量
局部变量 | 成员变量 | 类变量 | 实例变量 | |
---|---|---|---|---|
声明的位置 | 方法体、形参、代码块 | 类方法外 | - | - |
修饰符 | final | public protected,private,final ,static volatile,transient | static修饰 | 无static修饰 |
值存储位置 | 栈 | - | 方法区 | 堆 |
作用域 | - | - | 通过类名 | 通过对象名 |
生命周期 | - | - | 与类相同 | 与对象相同 |
-
局部变量:方法体中,形参,代码块中,可用final修饰
-
成员变量:类方法外,可用public protected,private,final ,static volatile,transient修饰
-
类变量:static修饰
-
实力变量:无static修饰
SSM面试题
Spring Bean 的 作用域之间有什么区别?
bean的作用域:可以使用scope属性来指定bean的作用域
-
singleton:默认值,当IOC容器一创建就会创建bean的实例,而且是单实例的
-
prototype:原型的,当IOC容器一创建不会实例化该bean,每次调用getBean方法时才会实例化该bean,不是单实例的
-
request:每次请求实例化一个bean
-
session:在一次会话中共享一个bean
Spring支持的常用数据库事务传播属性和隔离级别
事务的属性:@Transactional
-
propagation:用来设置事务的传播行为
-
isolation:用来设置事务的隔离级别
事务的传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播,例如方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行,事务传播的行为有传播属性指定,Spring定义了7中类传播行为
传播属性 | 描述 |
---|---|
REQUIRED默认 | 如果有事务在运行,当前的方法就在这个事务内运行,否则就启动一个新的事务,并在自己的事务内运行 |
REQUIRED_NEW | 当前方法必须启动事务,并在它自己的事务内运行,如果有事务正在运行,应该将他挂起 |
SUPPORTS | 如果有事务在运行,当前的方法就在这个事务内运行,否则他可以不运行在事务中 |
NOT_SUPPORTE | 当前的方法不应该运行在事务中,如果有运行的事务,将他挂起 |
MANDATORY | 当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常 |
NEVER | 当前方法不应该运行在事务中,如果有运行的事务,就抛出异常 |
NESTED | 如果有事务在运行,当前的方法就应该在这个事物的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行 |
事务隔离级别
数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。
隔离级别 | 脏读 | 不可重复读 | 幻读 | Oracle | MySQL |
---|---|---|---|---|---|
读未提交:READ UNCOMMITTED | 有 | 有 | 有 | × | √ |
读已提交:READ COMMITTED | 无 | 有 | 有 | √默认 | √ |
可重复读:REPEATABLE READ | 无 | 无 | 有 | × | √默认 |
串行化:SERIALIZABLE | 无 | 无 | 无 | √ | √ |
脏读:一个事务访问到了其他事务未提交的数据更改
不可重复读:在一个事务中进行了两次查询操作,得到的数据内容不一致
幻读:在一个事务中进行了两次查询操作,得到的行数不一致
事务
事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果将使数据库从一种一致性状态变迁到另一种一致性状态。事务是逻辑上的一组操作,要么全部执行,要么全部不执行
事务的基本步骤:
1.开启事务
START TRANSACTION 或者BEGIN
2.回滚事务(rollback)
3.提交事务
COMMIT
事务四大特征:
-
原子性:事务是最小的执行单位,不允许分割。
-
一致性:执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的。
-
隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的
-
持久性:一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响
SpringMVC中如何处理POST中文乱码问题,GET又如何呢?
修改配置文件WEB-INF/web.xml
<!--配置请求编码-->
<filter>
<filter-name>encodeFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
GET:修改tomcat的配置文件 server.xml ,在第一个 connector 标签里加 URIEncoding="UTF-8" 即可
SpringMVC的工作流程
Mybatis中当实体类中的属性名和表中的字段不一样,怎么办?
-
写SQL语句的时候,写别名
-
在MyBatis的全局配置文件中开启驼峰命名规则
<setting name="mapUnderscoreToCameLCase" value="true" />
-
在Mapper映射文件中使用resultMap自定义映射
<resultMap type="com.atguigu.pojo.Employee" id="myMap">
<!-- 映射主键 -->
<id cloumn="id" property="id"/>
<!-- 映射其他列 -->
<result column="last_name" property="lastName" />
<result column="email" property="email" />
<result column="salary" property="salary" />
<result column="dept_id" property="deptId" />
</resultMap>
Linux面试题
git分支相关命令
//创建分支
git branch <分支名>
git branch -v 查看分支
//切换分支
git checkout <分支名>
一步完成: git checkout -b <分支名>
//合并分支
先切换到主干 git checkout master
git merge <分支名>
//删除分支
先切换到主干 git checkout master
git branch -D <分支名>
git工作流
Redis面试题
Redis持久化有几种类型,它们的区别?
RDB
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
备份是如何执行的?
Redis会单独创建(fork) 一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
优点:
-
节省磁盘空间
-
恢复速度快
缺点:
-
虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。
-
在备份周期在一定间隔时间做一次备份, 所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。
AOF
以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,换言之,Redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
优点:
-
备份机制更稳健,丢失数据概率更低。
-
可读的日志文本,通过操作AOF稳健,可以处理误操作。
缺点:
-
比起RDB占用更多的磁盘空间。
-
恢复备份速度要慢。
-
每次读写都同步的话,有一定的性能压力。
-
存在个别Bug,造成不能恢复。
Redis在项目中的使用场景
数据类型 | 使用场景 |
---|---|
String | 比如说,我想知道什么时候封锁一个 IP 地址 Incrby 命令 |
Hash | 存储用户信息[ id, name , age] Hset( key ,field, value) Hset( key ,id, 101) Hset( key ,name, admin) Hset( key ,age, 23) 修改案例--------- Hget(userKev,jd)+ Hset(userKey,id,102) 为什么不使用String类型来存储 String拿到对象值之后需要反序列化,我们只需要更改id name, age 没有意义反序列化 Set(userKey;用信息的字符串) Get(userKey) 不建议使用String 类型。 |
List | 实现最新消息的排行,还可以利用 List 的 push 命令,将任务存在list集合 中,同时使用另-个命令,将任务从集合中取出[ pop ]。。 Redis - List 数据类型来模拟消息队列。[电商中的秒杀就可以采用这种方式 来完成一个秒杀活动]。 |
Set | 特殊之处:可以自动排重。比如说微博中将每个人的好友存在集合( Set) 中,+ 这样求两个人的共通好友的操作。我们只需要求交集即可。 |
Zset | 以某一个条件为权重,进行排序。 京东:商品详情的时候,都会有一个综合排名,还可以按照价格进行排名 |
MySQL面试题
MySql什么时候适合建索引,什么时候不适合建索引?
索引Index:帮助MySQL高校获取数据的数据结构。检索、排序快,更新慢、占用一定空间
那些情况需要创建索引
-
主键自动建立唯一索引
-
频繁作为查询条件的字段应该创建索引
-
查询中与其它表关联的字段,外键关系建立索引
-
单键/组合索引的选择问题,组合索引更好
-
意询中排序的字段,排序字段若通过索引访问将大大提高排序速度
-
查询中统计或者分组字段
那些情况下不要建立索引
-
表记录太少
-
经常增删改的表或字段,因为每次更新不仅更新记录还会更新索引
-
where条件里用不到的字段不创建索引
-
过滤性不好的不适合建索引
JVM面试题
JVM垃圾回收机制,GC发生在JVM哪部分,有几种GC,他们的算法是什么?
GC主要关注于方法区和堆中的垃圾收集,Java堆是垃圾收集器的工作重点
-
频繁收集Young区
-
较少收集Old区
-
基本不收集Perm区(元空间)
标记算法:
引用计数算法:对每个对象保存一个整型的引用计数器属性。用于记录对象被引用的情况。
优:
实现简单,垃圾对象便于辨识;判定效率高,回收没有延迟性。
缺:
-
它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。
-
每次赋值都需要更新计数器,伴随着加法和减法操作,这增加了时间开销。
-
引用计数器有一个严重的问题,即无法处理循环引用的情况。这是一条致命缺陷,导致在Java的垃圾回收器中没有使用这类算法。
可达性分析算法:以根对象集合(GCRoots)为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达。
GC Roots可以是哪些?
-
虚拟机栈中引用的对象
比如:各个线程被调用的方法中使用到的参数、局部变量等。
-
本地方法栈内JNI(通常说的本地方法)引用的对象方法区中类静态属性引用的对象
比如:Java类的引用类型静态变量
-
方法区中常量引用的对象
比如:字符串常量池(string Table)里的引用
-
所有被同步锁synchronized持有的对象
-
Java虚拟机内部的引用。
基本数据类型对应的Class对象,一些常驻的异常对象(如:NullPointerException、outofMemoryError),系统类加载器。
-
反映java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。
垃圾收集算法:
标记-清除算法(Mark-Sweep):从根节点开始标记所有被引用的对象,回收不可达对象(保存在空闲列表(内存不规整)中)
复制算法(copying):将内存空间分为两块,每次只使用其中一块,在垃圾回收时将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换两个内存的角色,最后完成垃圾回收
标记-整理算法(Mark-Compact):从根节点开始标记所有被引用对象,将所有的存活对象压缩到内存的一端,按顺序排放。之后,清理边界外所有的空间。
在HotSpot中,分代收集:
-
年轻代:复制算法
-
老年代:标记清除或标记清除与标记压缩混合实现
如何判断一个对象可以被回收?
-
引用计数算法
维护一个计数器,如果有对该对象的引用,计数器+1,反之-1。无法解决循环引用的问题。
-
可达性分析算法
从一组名为“GC Roots”的根节点对象出发,向下遍历。那些没有被遍历到、与GC Roots形成通路的对象,会被标记为“回收”。
哪些对象可以作为GC Roots?
-
虚拟机栈(栈帧中的局部变量)中引用的对象。
-
本地方法栈(native)中引用的对象。
-
方法区中常量引用的对象。
-
方法区中类静态属性引用的对象。
其他
Elasticsearch 与 solr 的区别
他们都是基于 Lucene 搜索服务器基础上开发,一款优秀的,高性能的企业级搜索服务器,【是因为他们都是基于分词技术构建的倒排索引的方式进行查询】
区别:
-
当实时建立索引的时候,solr 会产生 io 阻塞,而 es 不会,es 查询性能要高于 solr
-
在不断动态添加数据的时候,solr 的检索效率会变得低下,而 es 没有什么变化
-
Solr 利用 zookeeper 进行分布式管理,而 es 自带有分布式系统的管理功能,Solr 一般都要部署到 web 服务器上,比如 tomcat,启动 tomcat 的时候需要配置 tomcat 和 solr 的 关联 【 Solr 的本质,是一个动态的 web项目】
-
Solr支持更多格式的数据 【xml、json、csv 】等,而 es 仅仅支持 json 文件格式
-
Solr 是传统搜索应用的有利解决方案,但是 es 更加适用于新兴的是是搜索应用
-
单纯的对已有的数据进行检索, solr 效率更好,高于 es
-
Solr 官网提供的功能更多哦,而 es 本身更加注重于核心功能,高级功能都有第三方插件完成
单点登录
一处登录多处使用!单点登录多使用在分布式系统中
购物车实现过程
-
购物车跟用户的关系 ?
一个用户必须对应一个购物车
单点登录一定要在购车前
-
未登录将数据保存到什么地方?
Redis —京东
Cookie 自己开发项目的时候【如果浏览器禁用Cookie】
-
用户登录状态
Redis 缓存中 【读写速度快】
Hash: Hset(key,field,value)
Key:user:userId,cart
Hset(key,skuId,value);
存在数据库中 【Oracle,mysql】
-
展示购物车
未登录状态显示,直接从 cookie 中 取得数据展示即可
登录状态,用户一旦登录,必须显示数据库【redis】 + cookie 中的购物车的数据
消息队列在项目中的使用
由于在高并发的环境下,来不及同步处理用户发送的请求,则会导致请求发生阻塞,比如说,大量的 insert,update 之类的请求同时到达数据库 MySQL, 直接导致无数的行锁表锁,甚至会导致请求堆积过多,从而触发 too many connections ( 链接数太多 ) 错误,使用消息队列可以解决 【异步通信】
异步,并行,排队
如:电商项目