Java面试技能
2020-12-22 15:06:59 0 举报
AI智能生成
21届毕业拿到7-8offer,包括华为、京东、美团。熟悉这些知识即可
作者其他创作
大纲/内容
Java面试技能大汇总
1、mysql
分页查询
where条件子句
is not null
between and
like
in
join连表查询
操作\t描述Inner join\t如果表中至少有一个匹配,就返回行left join\t即使左表中没有匹配,也会从左表中返回所有的值right jion\t即使右表中没有匹配,也会从右表中返回所有的值
自链接
一张表拆成两张表
分页和排序
分页
缓解数据库的压力,给人更好的体验
limit
语法 limit(查询起始下标,pagesize)
排序
order by
asc : 升序
desc : 降序
-- 排序: 升序ASC 降序 DESCSELECT xxFROM xxJOIN xxWHERE xxORDER BY xxASC || DESC
子查询
分组
group by
mysql函数
数学运算
SELECT ABS(-8) -- 绝对值SELECT CEILING(9.4) -- 向上取整SELECT FLOOR(9.4) -- 向下取整SELECT RAND() -- 返回0-1随机数SELECT SIGN(-10) -- 判断一个数的符号 0-0 负数返回-1 正数返回1
字符串函数
-- 时间跟日期函数(记住)SELECT CURRENT_DATE() -- 获取当前日期SELECT CURDATE() -- 获取当前日期SELECT NOW() -- 获取当前日期SELECT LOCATIME() -- 本地时间SELECT SYSDATE() -- 系统时间
-- 系统SELECT SYSTEM_USER()SELECT USER()SELECT VERSION()
聚合函数(常用)
函数名称\t描述COUNT()\t计数SUM()\t求和AVG()\t平均值MAX()\t最大值MIN()\t最小值
数据库加密
事务
要么都成功,要么都失败
事务的原则
ACID
原子性
Atomicity: 要么都成功,要么都失败
一致性
持久性
Durability:事务一旦提交,不可逆转,被永久持续到数据库中
隔离性
I :事务产生多并发情况下,互不干扰。
隔离性会产生很多问题
脏读: 一个事务读取了另外一个事务未提交的数据
不可重复读: 在一个事务内,多次读取同一行的数据时,读取到的结果不相同
幻读:一个事务内,读取到了,别的事务插入的数据,导致结果不一样,多了一行
-- mysql 自动开启事务提交SET autocommit=0 -- 关闭SET autocommit=1 -- 开启(默认的)-- 手动处理事务SET autocommit =0 -- 关闭自动提交-- 事务开启START TRANSACTION -- 标记一个事务的开始,从这个之后的SQP都在同一个事务内INSERT XXINSERT XX-- 提交 : 持久化(成功)COMMIT -- 回滚: 回到原来的样子(失败)ROLLBACK-- 事务结束SET autocommit = 1 -- 开启自动提交-- 了解SAVEPOINT 保存点名称 -- 设置一个事务的保存点ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点RELEASE SAVEPOINT 保存点 -- 删除保存点
实例
索引
主键索引只能有一个,唯一索引有多个
索引分类
1.主键索引
primary key : 唯一的标识,只能有一列作为主键,主键不可重复
2.唯一索引
unique key :
避免重复的列出现,唯一索引可以重复,多个列都可以标识唯一索引
3.常规索引
KEY/INDEX :
4.全文索引
fulltext
在特点的数据库引擎下才有,MyISAM快速定位数据
5.测试索引
索引的使用-- 1.在创建表的时候给字段增加索引-- 2.创建完毕后,增加索引
-- 显示所有的索引信息SHOW INDEX FROM 表-- 增加一个索引ALTER TABLE 表 ADD FULLTEXT INDEX 索引名(字段名)-- EXPLAIN 分析sql执行状况EXPLAIN SELECT * FROM student -- 非全文索引
索引在小数据的时候,用处不大,但是在大数据的时候,区别十分明显
索引原则索引不是越多越好不要对经常变动的数据加索引小数据量的表不需要加索引索引一般加在常用来查询的字段上
索引的数据结构Hash 类型的索引Btree: 默认innodb 的数据结构阅读: http://blog.codinglabs.org/articles/theory-of-mysql-index.html
规范数据库设计
三大范式
第一范式
1NF:原子性:保证每一列不可再分
第二范式
2NF : 前提:满足第一范式每张表只描述一件事情
第三范式
3NF:前提:满足第一范式和第二范式第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。(规范数据库的设计)
为什么需要数据规范化?信息重复更新异常插入异常删除异常无法正常显示异常删除异常丢失有效的信息
规范性和性能的问题关联查询的表,不得超过三张表考虑商业化的需求和目标(成本和用户体验) 数据库的性能更加重要再规范性能的问题的时候,需要适当的考虑一下,规范性故意给某些表加一些冗余的字段(从多表,变成单表)故意增加一些计算列(从大数据量降低为小数据量的查询:索引)
JDBC(重点)
数据库驱动
驱动:声卡,显卡,数据库
JDBC
SUN 公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库的)规范,JDBC这些规范的实现由具体的厂商去做对于开发人员来说,我们只需要掌握JDBC的接口操作即可
java.sqljavax.sql还需要导入数据库驱动包
锁
性能
乐观
悲观
操作类型
读锁(悲观,共享),同一数据允许多个操作同时进行读,
写锁(悲观,排他),写操作没有完成之前,不允许其他写锁和读锁
颗粒度
表锁
锁整张表,开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;
查看锁:show open tables;
解锁:unlock tables;
读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞。
行锁
每次操作锁住一行数据。开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。
支持事务
并发事务处理带来的问题
更新丢失
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新
脏读
事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求
不可重读
事务A读取到了事务B已经提交的修改数据,不符合隔离性
幻读
事务A读取到了事务B提交的新增数据,不符合隔离性
事务隔离级别
读未提交
可能出现脏读
可能出现不可重复读
可能出现幻读
读已提交
不能出现脏读
可重复读
不能出现不可重复读
可串行化
都不能出现
优化
尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁合理设计索引,尽量缩小锁的范围尽可能减少检索条件范围,避免间隙锁尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql尽量放在事务最后执行尽可能低级别事务隔离
分库分表
垂直拆分
一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到不同的数据库上面,这样也就将数据或者说压力分担到不同的库上面
优点
1拆分后业务清晰,拆分规则明确
2. 系统之间整合或扩展容易。
3. 数据维护简单。
缺点
1. 部分业务表无法join,只能通过接口方式解决,提高了系统复杂度。
2. 受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高。
3. 事务处理复杂。
水平拆分
垂直拆分后遇到单机瓶颈,可以使用水平拆分。相对于垂直拆分的区别是:垂直拆分是把不同的表拆到不同的数据库中,而水平拆分是把同一个表拆到不同的数据库中。相对于垂直拆分,水平拆分不是将表的数据做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中 的某些行切分到一个数据库,而另外的某些行又切分到其他的数据库中,主要有分表,分库两种模式
1. 不存在单库大数据,高并发的性能瓶颈。
2. 对应用透明,应用端改造较少。
3. 按照合理拆分规则拆分,join操作基本避免跨库。
4. 提高了系统的稳定性跟负载能力。
1. 拆分规则难以抽象。
2. 分片事务一致性难以解决。
3. 数据多次扩展难度跟维护量极大。
4. 跨库join性能较差。
存储引擎
MYISAM
数据文件和索引文件分开(非聚集)frm+MYD+MYI
不支持事务,不支持行级锁
innodb
表数据文件就是按B+tree组织的索引结构文件(聚集),frm(表结构)+ibd
包含了完整的数据记录
主键索引包含数据,非主键索引不包含数据,只包含主键值,(基于数据一致性与节省空间考虑)
支持事务(TRANSACTION)支持行级锁
MySQL支持两种方式的排序filesort和index,Using index是指MySQL扫描索引本身完成排序。index效率高,filesort效率低。
、order by满足两种情况会使用Using index。1) order by语句使用索引最左前列。2) 使用where子句与order by子句条件列组合满足索引最左前列。
3、尽量在索引列上完成排序,遵循索引建立(索引创建的顺序)时的最左前缀法则。
、如果order by的条件不在索引列上,就会产生Using filesort。
单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序;
双路排序:是首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行 ID,然后在 sort buffer 中进行排序,排序完后需要再次取回其它需要的字段
能用覆盖索引尽量用覆盖索引
group by与order by很类似,其实质是先排序后分组,遵照索引创建顺序的最左前缀法则。对于groupby的优化如果不需要排序的可以加上order by null禁止排序。注意,where高于having,能写在where中的限定条件就不要去having限定了
2、java基础
入门
特点
简单
面向对象
跨平台
安全
多线程
八大基本类型
整形
byte
short
int
long
浮点型
float
double
字符型
char
布尔型
boolean
作用域和权限
private:只能本类使用
默认(default ):本类和子类可以使用
protected:本类,子类,同包
public:都可以使用
运算符
==和equals
算数运算符
关系运算符
位运算符
逻辑运算符
赋值运算符
条件运算符(三元运算符)
循环结构
do..while
while
for
普通for循环
增强for循环
break
continue
条件语句
if
if..else
if..else if..else
switch case
数组
定义
一维数组
数组类型[] 数组名 = [数据1,数据2]
数组类型[] 数组名 = new 数组类型[数组大小]
多维数组
数组类型[][] 数组名 = new 数组类型[数组大小][数组大小]
优缺点
查询效率比较高
可以容纳基本类型
数组的长度是固定的,不能改变
数组存储的类型必须是设置的存储类型
删除和插入比较慢,每次删除和插入会从新排序
方法(函数)
使程序变得简短而清晰
有利于程序维护
可以提高程序开发的效率
提高了代码的重用性
插入排序
直接插入排序
希尔排序
选择排序
简单选择排序
堆排序
交换排序
冒泡排序
快速排序
归并排序
基数排序
数据结构
队列
栈
链表
单链
双链
循环链表
块级链表
树
二叉树
类装载器
static修饰
方法
变量
代码块
重载(Overload)
封装
好处
良好的封装能够减少耦合
类内部的结构可以自由修改
可以对成员变量进行更精确的控制
隐藏信息,实现细节
例子
继承
特性
子类拥有父类非 private 的属性、方法
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展
子类可以用自己的方式实现父类的方法
Java 的继承是单继承,但是可以多重继承
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)
关键字
extends(继承)
implements(实现)
构造方法
注意
方法名和类名要一致
无返回值修饰符
不能被直接调用
由 new 关键字自动调用
可以使用return关键字(结束方法体)
不能用static修饰
可以重载
不可以被继承
重写(Override)
规则
多态
重载式多态
重写式多态
向上转型
向下转行
抽象
如果一个类包含抽象方法,那么该类必须是抽象类。
任何子类必须重写父类的抽象方法,或者声明自身为抽象类
规定
抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象
抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能
构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法
抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类
接口(Interface)
接口与类
相同点
一个接口可以有多个方法
接口文件保存在 .java 结尾的文件中,文件名使用接口名
接口的字节码文件保存在 .class 结尾的文件中
接口相应的字节码文件必须在与包名称相匹配的目录结构中
区别
接口不能用于实例化对象
接口没有构造方法
接口中所有的方法必须是抽象方法
接口不能包含成员变量,除了 static 和 final 变量
接口不是被类继承了,而是要被类实现
接口支持多继承
接口和抽象类的区别
抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行
抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的
接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法
一个类只能继承一个抽象类,而一个类却可以实现多个接口
接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字
接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字
接口中的方法都是公有的
final修饰
类
jvm
类装载器:将java文件加载成.class文件
字节码执行引擎
内存模型
线程共用
堆
方法区(元空间)
线程独有
栈帧
局部变量表
操作数栈
动态链接
方法出口
程序计数器
本地方法栈
api
java.lang
exception
异常处理
try..catch
finally
throws
throw
thread
Thread()
Thread(Runnable target)
Thread(String name)
sleep(long millis)
start()
toString()
getName()
getPriority()
interrupted()
java.util
date
Date()
Date(long date)
after(Date when)
before(Date when)
getTime()
setTime(long time)
Collection
子类
List
ArrayList
构造器
public ArrayList()
public ArrayList(ICollection)
public ArrayList(int)
LinkedList
LinkedList()
LinkedList(Collection<? extends E> c)
Set
HashSet
HashSet()
HashSet(Collection<? extends E> c)
HashSet(int initialCapacity)
TreeSet
使用方式
自然排序(Comparable)
比较器排序(Comparator)
TreeSet()
TreeSet(Collection<? extends E> c)
TreeSet(Comparator<? super E> comparator)
TreeSet(SortedSet<E> s)
Map
Map接口和Collection接口的不同
功能
添加功能
删除功能
判断功能
获取功能
长度功能
HashMap
HashMap()
HashMap(int capacity)
TreeMap
TreeMap()
TreeMap(Comparator<? super K> comparator)
java.util.concurrent
java.io
File
File(String pathname)
File(URI uri)
mkdir()
OutputStream
OutputStream()
close()
flush()
write(byte[] b)
write(int b)
InputStream
InputStream()
mark(int readlimit)
read()
read(byte[] b)
reset()
Writer
Writer()
Writer(Object lock)
append(char c)
write(char[] cbuf)
write(int c)
Reader
Reader()
Reader(Object lock)
mark(int readAheadLimit)
read()
read(char[] cbuf)
read(CharBuffer target)
ready()
接口
Serializable
java.math
java.nio
泛型
类型通配符
内部类
成员内部类
局部内部类
匿名内部类
静态内部类
反射
用途
反射相关类
3、jvm
运行时数据区域
程序计数器PCR
1.较小的内存
2.当前线程执行的字节码行号指示器
3.字节码指示器:通过改变这个计数器的值来选取下一条需要执行的指令
4.线程私有
6.不会内存溢出
java虚拟机栈
1.线程私有
2.生命周期和线程相同
3.每个方法创建栈帧
1.局部变量表
C.所需的内存在编译器就确定
2.操作数栈
3.动态连接
4.返回地址
5.异常情况
A:线程请求的栈深度大于虚拟机允许的深度
2.执行的是native方法
3.异常情况和虚拟机栈相同
Java 堆
1.jvm中内存最大的一块
2.线程共享
3.存放对象实例
4.垃圾回收的主要区域
5.新生代
1.Eden
2.From Survivor
3.To Survivor
6.老年代
7.多个线程私有的分配缓存区TLAB
8.物理上不连续的内存空间
9.异常:内存溢出
(永久代)方法区
1.线程共享
3.运行时常量池(存储编译器生成的字面量和符号引用)
直接内存
NIO中使用这块内存居多
非堆内存受总内存大小限制
对象的创建
1.new 指令创建对象
A:检查这个指令的参数能否在常量池中找到类的符号引用
C:没有的话先进行类加载过程
2.分配内存方式
A:指针碰撞
B:空闲列表
D:并发情况下线程不安全
同步
按照线程划分在不同的空间TLAB
3.对象的内存布局
A:对象头
第二部分类型指针(通过这个指针确定是哪个类的实例)
数组的话还存储数据的长度
B:实例数据
存储顺序受分配策略的影响:相同宽度的字段总是被分配到一起
父类中的字段信息在子类之前
C:对齐填充
虚拟机要求对象大小是8字节的整数倍
4.对象的访问定位
直接指针访问 详细看对象指针图 优点:速度块
内存分配策略
年轻代
对象主要分配在新生代的Eden区域
老年代
大对象直接进入老年代
长期存活的对象进入老年代
1.虚拟机给对象添加年龄计数器
2.动态年龄判断
3.空间分配担保
常用的工具
jps 显示指定系统内所有的虚拟机进程
jstat 监视虚拟机各种运行状态的信息
jmap 生成堆转储快照
jhat 虚拟机堆转储快照分析工具
jstack 生成虚拟机当前时刻的线程快照
类文件结构
class文件是一组以8字节为基础单位的二进制流
由无符号数和表构成
实战
Java 堆溢出
虚拟机栈溢出
本地方法栈溢出
方法区溢出
常量池溢出
本机直接内存溢出
垃圾回收
对象回收的判断
1.引用计数算法
优点:判定效率高
2.可达性分析算法
GC Roots\
作为GC Roots对象
栈帧中本地变量表中引用的对象
方法区类静态属性引用的对象
方法区中常量引用的对象
方法栈JNI引用的对象
强引用 Object obj = new Object
软引用 有用非必须
弱引用 非必须
虚引用 最弱的引用
不可达对象是否死亡判断
第一次标记 是否执行finalize
第二次标记 finalize方法是否可以和Gc root重新建立关系
枚举根节点
安全点
安全区域
方法区回收
垃圾回收效率较低
回收内容
废弃常量
无用类
1.该类所有实例都被回收
2.加载该类的ClassLoader被回收
垃圾收集算法
标记清除算法(最基础算法)
1.首先标记出所有需要回收的对象
2.在标记完成后统一回收掉所有被标记的对象
缺点1:标记和清除过程的效率都不高
缺点2:产生大量不连续的内存碎片
复制算法
1.内存按容量划分为大小相等的两块
3.将都是垃圾对象的那块清空内存
缺点1:在对象存活率较高时,复制操作次数多,效率降低
缺点2:內存缩小了一半;需要額外空间做分配担保(老年代)
标记整理算法
1.标记步骤和标记清除算法相同
分代收集算法
新生代
标记-清理或者标记-整理
垃圾收集器
Serial(最基本的收集器)
单线程
ParNew收集器
Serial的多线程版本
Parallel Scavenge收集器
新生代收集器
吞吐量较高
Serial Old收集器
Serial的老年代版本
Parallel Old收集器
Parallel的老年代版本
CMS收集器
回收停顿时间短
标记-清除
1.初始标记
2.并发标记
3.重新标记
4.并发清除
G1收集器
并行并发
分代收集
空间整合
可预测停顿
GC日志
GC日志最前面时间是虚拟机启动以来经过的秒数
【GC 【Full GC 垃圾收集的停顿类型
类加载机制
什么是类的加载机制
类加载的生命周期
加载
1.通过类的全限定名称获取此类的二进制流
2.将这个二进制字节流所代表的静态存储结构转化为方法区的运行时数据结构
5.加载和连接是交叉进行的
连接
验证
确保Class文件的字节流中包含的信息符合当前虚拟机要求
文件格式验证
元数据验证
字节码验证
符号引用验证
准备
为类变量分配内存并设置类变量初始值
解析
1.类或接口的解析
2.字段解析
3.类方法解析
4.接口方法解析
初始化
执行构造器 <clinit>
收集类中所有类变量的赋值动作和静态语句块中的合并语句
子类的clinit()执行之前,父类clinit()一定执行完成
不会执行父接口的(),除非要使用父接口中定义的变量
使用
卸载
类加载器
双亲委派模型
启动类加载器(虚拟机中的一部分)
将虚拟机识别的类库加载到内存
其他的类加载器(独立于虚拟机外部)
扩展类加载器
应用程序类加载器
负责加载ClassPath上指定的类库
自定义类加载器
工作过程
虚拟机字节码执行引擎
运行时栈帧结构
动态连接
方法返回地址
分派
静态分派
4、juc
1、JUC是什么
java.util.concurrent在并发编程中使用的工具类
进程/线程回顾
进程、线程是什么
进程、线程的例子
线程状态
wait和sleep的区别
什么是并发?什么是并行
2、锁
synchronized
多线程编程模板
线程、操作。资源类
高内聚、低耦合
实现步骤
1、创建资源类
2、资源类里面创建同步方法、同步代码块
Lock
lock是什么?
Lock接口的实现
与synchronized的区别
创建线程的方法(实现Runnable)
新建类实现runnable接口
lambda表达式
3、Java8与Lambda表达式
lambda表达式?
是什么?
要求
写法
函数式接口
接口中也可以有实现方法
4、线程间通信
5、多线程锁
6、集合不安全
7、callable接口
0 条评论
回复 删除
下一页