IO
按照流的流向分类:输入流和输出流
按照操作单元分类:可以分为字节流和字符流
按照流的角色划分:节点流和处理流
所有输入流的基类:InputStream/Reader 字节流/字符流
所有输出流的基类:OutputStream/Reader 字节流/字符流
java八大基本类型
byte short int long float double boolean char
sleep和wait
sleep()方法可以在任何地方使用,wait()在同步只使用
sleep()不放弃对象锁 ,wait()放弃对象锁
sleep()为Thread的静态方法,wait()为Object的成员方法
进程和线程
进程为资源分配的最小单位
线程为CPU调度的最小单位
一个进程内部包含多个并发执行的线程
在进程内部多个线程共享一个进程资源
线程池的种类
可缓存线程池 newCachedThreadPool
单一线程池 newSingleThreadPool
定长线程池 newFixedThreadPool
线程池参数
核心线程大小 corePoolSize
最大线程数 maxPoolSize
空闲线程存活时间 keepAliveTime
拒绝策略 handler
线程工厂 threadFactory
时间单位 unit
工作队列 workQueue
序列化
序列化:把对象转化为可以传输的字节序列的过程
反序列化:将可传输的字节序列还原为对象的过程
目的:实现对象存储,实现网络传输
Http Https
http: 不安全 80端口 超文本传输协议 明文传输
https:http的加密通道 需要CA证书 安全 443端口
三次握手 四次挥手
第一次:
客户端:什么都不能确认
服务器:确定可以接受到客户端的请求
第二次:
客户端:自己发送,接受正常,对方发送,接受正常
服务器:自己接受正常, 对方发送正常
第三次:
客户端:自己发送,接受正常,对方发送,接受正常
服务器:自己发送,接受正常,对方发送,接受正常
TCP连接释放需要4个步骤,两次挥手就可以释放一段到另一端的连接,四次全部释放
TCP和UDP
TCP:有连接 资源需求多 数据安全 顺序结构 UDP: 无连接 资源需求少 会丢包 不保证顺序
get和post
get:通过请求行传递用户所输入的内容,其内容在浏览器上全部显示在地址栏上
有长度
不安全
post:将请求数据已表单的形式传输
没有提交长度
安全
排序算法
冒泡排序:比较相邻的两个元素,第一轮可以找到最大元素
插入排序:把新的元素插入到已排序好的队列中
选择排序:选出最大或最小的元素放在第一位,依次选择,直到元素个数为0
String StringBuffer StringBuilder
String:不可变,每次产生一个新的对象
StringBuffer:可变,性能好,安全,多线程
StringBuilder:可变,性能好,不安全,单线程
异常体系
throwable>error>exception
1.运行时异常
空指针异常 NullPointerExeception
字符串转化异常NumberFormatException
数组角标越界异常IndexOutOfBoundsException
方法传递参数错误IllegalArgumentException
数据类型转化异常ClassCastException
2.检查时异常
I/OException 输入输出异常
SQLException SQL异常
ClassNotFoundException 类加载异常
InterruptException 线程中断异常
分库分表
分库
-
将数据分散到多个数据库实例中。
-
每个数据库实例可以独立部署在不同的服务器上,以提高存储容量和并发处理能力。
-
适用于数据量非常大、单个数据库无法承载的情况。
分表
-
将数据分散到同一个数据库实例中的多个表中。
-
适用于单个表的数据量过大,导致查询和写入性能下降的情况。
-
可以在同一数据库实例中实现,也可以在不同的数据库实例中实现。
索引
主键索引特殊的唯一值不允许为空
唯一索引不允许索引值重复
普通索引纯粹为了查询快一点
联合索引为两个字段的索引
advice注解
@Before在方法执行前
@AfterReturning正常结束后拦截
@AfterThrowing异常时拦截
@After方法结束后拦截
@Around控制流程,加在哪里在哪执行
CGLIB和jdk
jdk对接口代理,使用反射机制实现AOP动态代理
CGLIB对类的代理,通过继承类的方式实现
@Autowired和@Resource
@Autowired是Spring的,默认byType,失败后用byName
@Resource是java的,byName自动注入
SpringBoot常用注解
@component 组件
@Service 业务层注解
@Repository 数据层
@Controller 控制层
java配置类相关注解
@Configration 配置类 @bean 容器管理 @ComponentScan 组件扫描 @EnableAspectAutoProxy 代理支持
@Scope 作用域 @Value 属性 @PropertySourse加在配置文件 @EnableScheduling 开启事务支持
切面相关注解
@Aspect标记为一个切面类
@After定义后置通知,在方法调用之后执行,无论是否抛出异常
@Before定义前置通知,在方法执行前生效
@PointCut定义切面表达式,一般在方法上
@AfterThrowing定义一个异常通知,在方法抛出异常后生效
@AfterReturning定义一个返回通知,在方法成功返回后执行
@Around环绕通知,方法前后均可调用,用于控制流程
依赖注入方式
属性注入
构造器注入
setter注入
Spring中bean的作用域
singleton单例 prototype原型 request请求 session会话 globalsession全局会话
SpringMVC Springcloud Springboot
SpringCloud构建于Springboot是微服务的全家桶
Spring是一个轻量级的控制反转,面相切面的容器框架,但他的配置是重量级的,所以推出Springboot,约定优于配置,开箱即用
SpringMVC流程
前段控制器DispatcherServlet------->处理器映射器handleMapping------>根据URL找到具体的处理器,生成处理器执行链,返回给DispatcherServlet-------->到处理器适配器HandleAdapter,执行一系列操作------>生成ModelAndView返回给前端控制器------->
到视图解析器ViewReslover解析成jsp---->相应给客户
SpringMVC常用注解
@Controller @RestController @ResponseBody @RequestBody @RequestMapping @PathVarible
mybatis 缓存
一级缓存sqlsession 二级缓存 namespace下的 二级缓存>一级缓存>数据库
分页
Mysql的limit
mybatis的pagehelper
说说你对缓冲穿透,缓存雪崩,缓存击穿的理解?
缓存穿透指的是在查询一个不存在的数据时,由于这个数据不在缓存中存在,并且也不存在于数据库,每次请求都会打到数据库,这样不仅会浪费数据库资源也没有有效的结果。
拦截非法请求,给不存在的对象设置空对象或默认值。
缓存雪崩在同一时刻大量缓存失效,导致大量请求打到后端数据库上,造成整个系统的崩溃。
分布式部署缓存,设置不同key的过期时间,多级缓存策略,对后台数据库进行限流,降级,熔断
缓存击穿某个热点数据忽然失效,大量请求访问数据库,导致数据库压力增大或垮掉。
给每个key设置合理的过期时间,加锁。
乐观锁和悲观锁
乐观锁:假设最好的情况出现,即大部分时间都不会来修改数据,因此不会在事务开始时就锁定数据,而是在提交前检查数据是否被其他事物修改。减少锁的竞争,提高并发效果。
悲观锁:假设最坏的情况出现,即认为每次事务都会对数据进行修改,在操作数据前锁定相关的数据。排它锁。解决高并发,确保事务一致性。造成死锁,资源利用低。
String转化为数组
String str= "apple,banana,orange";
String[] stringArray = str.split(",");
String str = "Hello, world!";
char[] charArray = str.toCharArray();
高并发问题解决方案?
负载均衡:避免单点过载。
缓存机制:减少对数据库的请求
异步处理:通过消息队列,实现异步任务处理。
索引优化:定期分析优化索引。
连接池:提高对数据库访问的效率。
熔断机制:当某个任务不抗用时,快速失败。
限流:限制单位时间内的访问请求。
降级处理:保证核心任务,减少功能。
加密算法
AES加密和解密流程
生成密
public static String generateAesKey() throws Exception {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256); // 128, 192, or 256 bits
SecretKey secretKey = keyGen.generateKey();
return Base64.getEncoder().encodeToString(secretKey.getEncoded());
}
加密
public static String encryptAes(String plaintext, String key) throws Exception {
SecretKey secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecureRandom random = new SecureRandom();
byte[] iv = new byte[cipher.getBlockSize()];
random.nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
byte[] encrypted = cipher.doFinal(plaintext.getBytes());
return Base64.getEncoder().encodeToString(iv) + ":" + Base64.getEncoder().encodeToString(encrypted);
}
解密
public static String decryptAes(String encryptedText, String key) throws Exception {
SecretKey secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
String[] parts = encryptedText.split(":");
byte[] iv = Base64.getDecoder().decode(parts[0]);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(parts[1]));
return new String(decrypted);
}
索引的数据结构
B+树
哈希
全文索引
R树
B+树优点
支持范围查询:所有叶子节点通过指针链接形成一个有序链表,便于查询
支持排序:叶子结点有序,支持排序操作
磁盘的读写效率高:层数少,减少I/O操作
较好的缓存机制:节点大小与磁盘大小匹配,充分利用缓存
支持多键值:每个节点可以存储多个键值对,减少I/O操作
垃圾回收机制
标记-清除:标记需要回收的对象,清除这些对象。产生碎片化内存。
复制:将内存复制为两份相等的区域,每次利用其中的一份,将利用之后存活的对象复制到另一份区域,然后清除这个区域。没有碎片化,内存利用率低。
标记-整理:与标记-清除一致,但在清理阶段将存活的对象向一段移动。没有碎片化。
分代收集:将堆内存分为新生代和老年代,使用不同算法,新生代使用复制算法,老年代使用标记-清除或标记-整理。
新生代和老年代
新生代:Eden区和Survivor区(s0 ,s1),新建的对象在Eden区,当Eden区满了,进行回收,将存活的对象移动到Survivor区,如果Survivor区满了,则晋升为老年代。
老年代:存放经过几轮回收都存活的对象。老年代的垃圾回收称为 Major GC 或 Full GC。
Redis持久化机制
AOF:Append Only File
以日志的形式记录每个操作。
将Redis执行过的指令全部记录下来。
只许追加文件,不允许修改。
在启动之初会读取该文件并从头到尾执行一遍。
RDB:Redis Database
在指定的时间内,将内存中的数据写入快照。
Redis数据结构和应用场景说一下?
Strings:缓存,会话管理,限流,计数器。
Lists:消息队列,任务队列,最新的N个数据。
Sets:去重,标签系统,权限管理。
哈希(hashes):对象存储,会话数据,配置管理。
有序列表(Sorted Sets):优先级队列,排行榜,时间序列数据。
了解Bean的加载过程吗?
解析xml:解析出bean的定义信息
注册Bean:将解析出的信息注册到BeanFactory
实例化Bean:创建Bean的实例
注入属性:依赖注入
初始化前处理:实现Initialization接口,init-methed
Aware接口回调:BeanByName,BeanFactoryAware
初始化后处理:
使用Bean:完全初始化后
销毁Bean:destroy-method
JVM内存分为几个区?这些区分别有哪些作用?
1.方法区
方法区也是各个线程共享的内存区域,用于存储已被虚拟机加载的类对象,常量,静态变量、即编译器编译后的代码和数据。在jdk8之前,也被称为永久代,在jdk8之后,永久代被元空间取代,元空间使用的是本地内存,而不是虚拟机内存。
2.Java虚拟机栈
java虚拟机栈也就是平时我们说的栈内存,服务于java方法,每个方法执行后都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。
虚拟机栈中的线程是私有的,生命周期的线程的一样。
3.本地方法栈
本地方法栈和java虚拟机栈类似,只不过它是为本地方法服务。
4.程序计数器
每个线程都有一个独立的程序计数器,用于记录当前线程所执行的字节码指令的位置。如果正在执行的线程是一个java方法,则记录正在执行的字节码指令的地址,如果这个线程是一个本地方法,则记录为空。
5.堆
堆内存是所有线程共享的一个内存区域,在虚拟机启动时创建。这个区域存放对象实例,几乎所有的对象实例都在这里分配内存。这里是垃圾收集器管理的区域,采用分代收集算法,一般分为新生代(Eden和Survivor)和老年代。
6.运行时常量池
运行时常量池是方法区的一部分,用于存储编译后生成的各中字面量和符号引用。
MYSQL事务
1.事务的基本要素(ACID)
原子性:事务开始后的操作,要么全部做完,要么全部不做,不可能停滞在中间环节。中间环节出错会回滚到事务开始时刻的状态。
一致性:事务开始前和结束后,事务的完整性约束不会被破坏。例如A向B转钱,A减少了,B没增加。
持久性:事务完成后,事务对数据库所有的数据进行更新,不能回滚。
隔离性:同一时间,只允许一个事务请求同一数据,不同的事务之间没有干扰。
2.MYSQL事务的隔离级别
读未提交:产生脏读,不可重复读,幻读
读已提交:产生不可重复读,幻读 MYSQL的默认级别
可重复读:产生幻读 Oracle的默认级别
串行化:最高级别不产生并发问题
3.事务产生的并发问题
脏读:事务A读取了事务B更新的数据,然后事务B进行回滚,那么A读取的就是脏数据。
不可重复读:事务A多次读取同一数据,事务B在事务A多次读取中对这个数据进行更新并提交,导致事务A多次读取的数据不一致。
幻读:事务A将所有的数据进行更改,这时候事务B添加了一条数据进来,导致事务A发现还有一条数据没有改过来。
4.Spring中事务的管理
声明式事务:用在Spring配置文件中声明式事务的处理事务来代替代码的处理事务,利用@TranactionManager来指定一个事务管理器,使用@Tranactional注解来开启对事物的管理,可以使用在方法,接口,类上面。
5.Redis中的事务
Redis是有事务的,它的事务就是一组命令的集合,这组命令要么都不执行,要么都执行。
Redis的事务除了要保证所有命令都要全部执行或全部都不执行外,还要要保证命令依次执行不允许打乱顺序,而且Redis的事务不能回滚。
什么情况下索引会失效?
1.where后面使用函数或计算
explain Select * from Test_1 where age = 20
explain Select * from Test_1 where age + 10 =20
2.使用or条件
explain Select * from Test_1 where Name = '吕布' or Name = 'aaa'
3.模糊查询%放在前面
explain Select * from Test_1 where Name like '%吕布'
explain Select * from Test_1 where Name like '%吕布%'
explain Select * from Test_1 where Name like '吕布&'
4.类型的转换
explain Select * from Test_1 where Name = 11
explain Select * from Test_1 where Name = '11'
5.组合索引(靠左原则)
假设一个索引为Indexi_d_class_grade(包含Class字段和Grade字段)
explain Select * from Test_1 where id = 11 and class = '软件工程' And Grade = '20'
explain Select * from Test_1 where Grade = '20'And class = '软件工程' and id = 11
sql如何优化?
1.尽量选择较小的列
2.将where后面常用的条件建立索引
3.Select后面避免*
4.避免在索引上使用函数,NOT ,<>
5.当只需要一行数据时使用limit 1
6.适当分库分表
对于分库分表将一个数据库中的内容放在几个数据库中来存储,缓解单个数据库的压力
分表将一张表中的内容放在几张表中用过来提来查询的效率
7.尽量缩小条件的结果
volatile和synchronized?
1.volatile是最轻量级的同步机制,保证了线程的同步机制,被volatile修饰的变量,当这个值发生改变的时候其他线程立马可以看见。
2.volatile禁止指令重排,保证线程的有序进行。
3.synchronzied锁定当前变量,其他的线程不允许访问这个变量,被阻塞。
4.synchronized可以用在方法,类,变量上,而volatile仅用在变量上面。
5.synchronized保证线程的可见性和原子性,而volatile仅仅保证可见性不保证原子性。
6.synchronized可以被编译器优化,volatile不被编译器优化。
7.synchronized会造成线程堵塞,volatile不会造成线程堵塞。
synchronized锁定方法,类,变量,造成堵塞,编译器优化,保证了原子性和可见性
volatile只作用于变量,不会造成堵塞,不被编译器优化,只保证可见性,禁止指令重排,保证线程有序进行
java类加载过程?
加载
通过一个类的全限定名获取他的二进制文件,将二进制流转化为运行时数据结构,在内存中生成他的Class对象,作为该类的数据访问接口。
验证
保证Class文件不会对虚拟机造成破坏
文件格式验证:验证是否符合Class文件的规范
元数据验证:对字节码描述的信息进行验证,进行语义分析
字节码验证:最复杂的流程,主要是对方法进行验证,对数据流和控制流进行分析,确定语义的正确性。
解析:符号引用验证:保证解析动作可以顺利发生。
准备
为类的静态变量分配内存进行初始化为默认值,都在方法区,不分配类中的实例对象的内存,这个在实例化中分配内存
初始化
初始化时类加载的最后一步,执行java程序代码。
Redis为什么快?
完全基于内存,绝大部分请求的都是直接对内存的操作,在内存中类似于hashmap优势在于时间复杂度为O(1)
数据结构简单
采用单线程,避免了不必要的上下文切换,避免资源竞争
使用I/O多路复用模型,非阻塞IO
底层模型为Redis自己构建的VM机制
hashmap 和 hashtable 的区别?
线程安全性问题
hashmap是线程不安全的,hashtable是线程安全的,其中就是synchronized方法,在多线程情况下,可以直接使用hashtable,如果想使用hashmap,就需要自己加入同步机制处理
key value 是否为空
hashmap中null可以作为键,值也可以为空,但只有一个空键,而hashtable不允许键值为空
是否包含contains方法
在hashmap中只有containskey,containsValue方法,而hashtable有contains,containsKey,containsValue三个方法
数组初始化和扩容机制
hashtable中默认为11容量,hashMap默认为16
hashtable不要求底层数组容量为2的整数次幂,hashMap要求底层数组容量为2的整数次幂
hashtable扩容时为原来的两倍加1,hashmap扩容为原来的两倍
线程创建的4种方式
package com.yd.chll.day06;
import org.omg.CORBA.TIMEOUT;
import javax.naming.ldap.ExtendedRequest;
import java.util.concurrent.*;
public class TestThread {
public static void main(String[] args) throws Exception {
//继承Thread类
ThreadClass threadClass = new ThreadClass();
threadClass.start();
Thread.sleep(100);
System.out.println("================");
//实现runnable接口
RunnableClass runnableClass = new RunnableClass();
new Thread(runnableClass).start();
Thread.sleep(100);
System.out.println("================");
//使用CallAble
FutureTask futureTask = new FutureTask(new CallableClass());
futureTask.run();
System.out.println("返回值:" + futureTask.get());
Thread.sleep(100);
System.out.println("===================");
//使用线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 2, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));
threadPoolExecutor.execute(threadClass);
threadPoolExecutor.shutdown();
Thread.sleep(100);
System.out.println("==================");
//使用并发包Executors
ExecutorService executorService = Executors.newFixedThreadPool(5);
executorService.submit(threadClass);
executorService.shutdown();
}
}
//继承Thread类
class ThreadClass extends Thread {
@Override
public void run() {
System.out.println("我是继承Thread类");
}
}
// 实现Runnable接口
class RunnableClass implements Runnable {
@Override
public void run() {
System.out.println("我是实现runnable接口");
}
}
//实现CallAble接口
class CallableClass implements Callable<String> {
@Override
public String call() {
System.out.println("我是实现Callable接口");
return "一个返回值";
}
}
1、继承Thread类
2、实现Runnable接口
3、使用CallAble和Faturetask
4、使用线程池创建
设置corePoolSize核心线程数,maximumPoolSize最大线程数,keepAliveTime存活时间,unit单位,workQueue工作队列
线程的状态转换?即生命周期
1.新建状态
线程刚被创建时为新建状态
2.就绪状态
也称为可执行状态,线程创建后调用了Start方法
3.运行状态
线程获取CPU时间片进行执行
4.阻塞状态
放弃运行状态进入到阻塞状态
等待阻塞 调用了wait方法,等待其他的线程完成,需要notify()和notifyall()唤醒。
同步阻塞 synchronized方法同步锁,锁被其他线程占用
其他阻塞 调用了sleep方法,join方法
5.死亡状态
线程执行运行完了,结束生命周期。
对于线程的整理?
1、生命周期
2、创建线程的4中方式
3、多线程的同步机制
4、多线程的安全性
final finally finalize三者的区别?
final:这个关键字用于修饰类,变量,方法
修饰类时表示这个类不能再派生出子类,即这个类不能被继承,和abstract相反。
修饰变量时表示这个变量不可以在改变,即常量。
修饰方法时,只能被使用不能修改,不能再子类中重写。
finally:这个关键字通常放在try catch中使用,无论程序是否抛出异常都会执行这个代码块,一般用来释放资源。
finalize:这个关键字一般用在垃圾回收器中,用来清理整理系统资源。
Object中有哪些常用的方法?
protected Object clone()----> 创建并返回一个对象副本
boolean equals(Object obj)----> 指定某个对象和其他对象是否相等
protected void finalize()-----> 当垃圾回收器中不存在对象其他方法引用是,回收方法此对象
Class<? extendsObject> getClass() -----> 返回一个运行时对象
int hashCode() ----> 返回该对象哈希值
void notify() ----> 唤醒当前线程
void notifyAll() ------> 唤醒所有线程
String toString() ----> 返回的对象用字符串表示
void wait() -----> 当前线程进入等待状态
谈一谈死锁?
首先了解是死锁形成的四个条件
互斥条件:一个资源只能被一个线程使用
占有等待条件:一个线程在阻塞状态是等待其他资源,不释放自己的资源
不可抢占条件:一个线程已经获取的资源,在未使用完之前,其他线程不可抢占
循环等待条件:若干线程形成了头尾相连的循环等待资源
避免死锁
注意加锁的顺序
设置锁的时间
注意死锁检查,这是预防死锁的一种机制,确保在形成死锁的第一时间发现它
简单谈一下SpringMVC的工作流程?
1.用户发送请求到前段控制器DispatcherServlet
2.DispatcherServlet收到请求调用处理器映射器HandleMapping
3.处理器映射器找的具体的处理器,生成处理器对象及处理器拦截器一起返回给前端控制器DispatcherServlet
4.DispatcherServlet调用处理器适配器HandleAdapter
5.HandleAdapter调用后端控制器
6.后端控制器执行完返回ModerAndView
7.HandleAdapter将后端控制器的结果ModleAndView返回给DispatcherServlet
8.DispatcherServlet将ModleAndView 发送到视图解析器ViewReslover
9.ViewReslover解析ModleAndView出视图返回给DispatcherServlet
10.DispatcherServlet将视图响应给用户
谈一谈你对Spring的理解?
Spring是一个开源框架,为简化企业级应用开发而生。Spring可以使简单的JavaBean实现以前只有EJB才能实现的功能。Spring是一个IOC和AOP容器框架。
IOC:在传统的Java开发模式中,当我们需要一个对象是,一般都是自己new或者getInstance等直接或间接获取一个对象。而在Spring开发模式中,Spring容器使用了工厂模式为我们创建所需要的对象,不需要我们直接创建,直接调用Spring提供的对象就可以了,这是控制反转的思想。
AOP:面向切面编程,在OOP思想中,我们将事务纵向抽象成一个一个的对象。而在AOP思想中,我们将一个一个对象的某个共同属性看成一个切面,对这个切面进行一些例如权限控制,事务管理,记录日志,异常处理等公共操作处理的过程就是面向切面的思想。AOP的底层是动态代理,对于接口使用jdk动态代理,对于类采用cglib动态代理。
切面:这些对象的共同属性
通知:增强式事务
切入点:方法
连接点:方法调用
织入:不改变当前代码,对代码进行增强
Spring常用的设计模式?
1.代理模式------AOP的底层jdk动态代理和cglib动态代理
2.单例模式------Spring配置文件中Bean默认为单例模式。
3.模版方法模式------解决代码重复的问题
4.工厂模式------BeanFactory创建新的对象。
Spring Bean的生命周期?
1.默认情况
1、调用构造器或者通过工厂的方式创建Bean对象
2、给Bean对象注入属性
3、调用init_methed初始化方法
4、使用
5、IOC容器关闭、Bean调用destory_methed方法销毁
2、当加入Bean的后置处理器
1、调用构造器或者通过工厂的方式创建Bean对象
2、给Bean对象注入属性
3、执行后置处理器中的postProcesseBeforeInit方法
4、调用init_methed初始化方法
5、执行后置处理器中postProcessAfterInit方法
6、使用
7、IOC容器关闭、Bean调用destory_methed方法销毁
Mybatis中的#{}和${}占位符的区别?
1、#{}是预处理,${}是字符串替换
2、将SQL中的#{}替换为?,使用set方法设置值,而${}占位符替换其中的字符串
2、使用#{}可以预防SQL注入问题
Mybatis中一级缓存和二级缓存?
1、一级缓存为SqlSession,二级缓存为NameSpace
2、NameSpace>SqlSession>数据库
谈一下动态SQL?
在条件不确定的情况下去查询数据
常用标签:
1、<if> :进行条件判断
2、<where>: 在<if>判断后SQL中添加where,处理AND 和OR
3、<trim>: 指定添加或去除字符串
4、<set>: 修改逗号引发的问题
5、<foreach>: 迭代操作
6、<choose><when><otherwise>:在条件中选择一个
谈一谈怎么理解Springboot框架?
Springboot是Spring开源组织的一个子模块,开箱即用,主要简化了Spring的配置难度,提供了各种的启动器,可以快速上手。
优点:
1、独立运行
内嵌了各种servlet启动器,例如tomcat,jetty,只需要一个jar包就可以启动。
2、简化配置
spring-boot-starter-web启动器依赖中简化了Maven的配置
3、自动配置
添加一个spring-boot-starter-web启动器就能拥有web的功能
4、无代码生成和xml配置
基于注解开发
5、应用监控
提供一系列的端点用来监控服务和应用。
Springboot的核心注解?
SpringBootApplication
1、SpringBootConfigration:实现配置文件的功能
2、EnableAutoConfigration:打开自动配置
3、ComponentScan:用于组件扫描
SpringBoot和SpringCloud的关系?
Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;
springcloud离不开SpringBoot。
springcloud中的常用组件?
1、nacos------注册中心
2、gateway------网关
3、openfeign------远程调用
4、sentinel------容错机制
5、sleuth------链路追踪
MYSQL的索引为什么是B+树?
因为索引是用来快速查询的,而B+树通过对数据进行排序提高了查询速度,
通过一个节点可以存储多个键值对,使得B+树的层级不会太高,
在MYSQL的InnoDB也就是一个B+树节点,默认为16KB,所以一般情况下一个两层的B+树可以存储2000万行的数据,
然后通过B+树的叶节点存储了所有的数据并进行了排序,叶节点之间有指针链接,也可以支持全表扫描和范围查询。
如何处理慢查询?
首先我们要搞清楚慢查询的原因是什么?
是否使用索引?用explain看是否使用了索引
是不是查询了不需要的数据?去除不需要的数据
还是数据量太大?分库分表
overload和override区别?
重写是父类与子类中的多态的表现,对于重载他是一个类中多态的表现。重写要求方法名和返回类型都需要相同,在一个类中如果有多个方法名相同方法,其返回类型和参数不同。
对于Collection和Map?
这两个都是java.util的子包
对于collection,这个接口对List列表,set集合,queue队列支持。
对于List:有arraylist和linkedlist
都不是线程安全的,在多线程情况下,需要使用synchronized方法同步
arraylist
这是一个动态数组实现的List
支持高效率的随机访问。
对于修改来说比较方便。
适用于需要频繁访问或更改。
linkedlist
这个是一个双向链表。
对于增,删比较友好。
适用于需要频繁增加和删除的操作。
对于set:不包含重复元素的集合,有hashset和treeset
hashset:无序 linkedhashset: 排序好了
treeset:需要排序
对于queue:用于处理数据结构的队列
对于Map支持key,value映射,
主要实现hashmap和treemap
linkedhashmap基于哈希表和链表机构实现,保证插入顺序
谈一谈你对反射的理解?
1.反射机制是什么?
反射就是java语言在运行时拥有的自观的能力
java反射机制要借助4个类:
class类对象
constructor类的构造器
field 类的属性对象
method类的方法对象
2.反射机制的作用是什么?
在java运行时环境中,对于任意一个类可以获取它的属性和方法,对于任意一个对象可以获取它的方法。
这种动态获取类的信息和对象的信息就是源于java的反射机制
3.反射机制提供的功能?
在运行时判断任意一个对象所属的类
在运行时构造任意一个对象
在运行时判断任意一个对象的成员变量和方法
在运行时调用任意一个对象的方法
select_type类型有哪些?
1、SIMPLE 简单的查询不包含子查询或联合查询
2、PRIMARY 主查询 查询最外层的部分
3、SUBQUERY 子查询的第一个Select,通常出现在From子句中
4、DERIVER 从派生表中获取数据
5、UNION UNION中的第二个或后续的Select语句
6、UNION RESULT UNION的结果集合并,有去重操作
7、UNION ALL 结果合并 没有去重
对于布隆过滤器有了解吗?
布隆过滤器是一种空间效率高的概率性数据结构,布隆过滤器不能确定"元素一定不在集合中",但可以高效的回答"元素很可能在集合中"。
应用场景:
1、网页爬虫:网页爬虫是可以用来记录一个已经抓取的URL,避免重复。
2、缓存击穿:缓存击穿,可以快速判断一个数据是否在缓存中,避免直接从数据库中抓取数据。
3、大数据处理:在大数据处理中,可以快速过滤大量数据,减少不必要的计算和存储。
4、数据同步:在数据库同步中,可以确定哪些数据已经同步过。
5、搜索引擎:可以快速确定某些关键字是不是拥有索引
特点
允许误判
不可逆性
删除困难
空间效率高
查询效率高
Redis服务器的内存有多大?
Redis默认的大小为:
32位默认为3GB
64为不受限制
一般推荐Redis的内存大小就是最大物理内存的3/4
为什么Redis的操作是原子性的?
1、命令的原子性:一个操作不可以再分,操作要么执行,要么不执行。
2、Redis的操作之所以是原子性的,是因为Redis是单线程的。
3、Redis本身提供的API都是原子性的,Redis的事务就是保证操作的原子性。
Redis有没有事务?
Redis是有事务的,它的事务就是一组命令的集合,这组命令要么都不执行,要么都执行。
Redis的事务除了要保证所有命令都要全部执行或全部都不执行外,还要要保证命令依次执行不允许打乱顺序,而且Redis的事务不能回滚。
MYSQL中有大量数据,如何保证Redis中的数据都是热点数据?
Redis内存淘汰策略。
当Redis的内存大小上升到一定大小时,会进行数据淘汰策略。
数据淘汰策略:
noeviction:当内存溢出时,回收产生较大内存的指令。
allkeys-lru:尝试回收使用最少的键,让新的数据有空间来存放。
allkeys-random:随机回收键来存放新的数据。
volatile-lru:在过期的集合中回收使用最少的键,用来存放新的数据。
volatile-random:随机回收过期集合中的键用来存放新的数据。
volatile-ttl:在过期集合中,优先回收存货时间较短的键用来存放新的数据。
对于MYSQL数据库有哪些了解?
1、事务
1、事务的特性
2、事务的隔离级别
3、事务的并发问题
2、索引
1、索引的目的
2、索引的种类
3、索引的失效
3、数据库设计规范
4、动态SQL
规范化
1、第一范式:每一列都都是原子性的,不可再分。
2、第二范式:在第一范式的基础上,消除非主属性对部分键的依赖,即一张表描述一件事。
3、第三范式:在第二范式的基础上,消除属性的传递关系,即字段不可以被其他字段推导出来。
反规范化
为了提高查询性能而有意引入的冗余数据,虽然会增加存储空间和更新复杂度,但可以显著的提高查询效率。 、
4、SQL优化
1、尽量选择较小的列
2、在where后面常用的字段添加索引
3、当我们只需要一行数据的时候用limit 1
4、避免Select * 操作
5、分库分表
6、尽量缩小条件的结果
7、避免在索引上使用函数和计算
5、分库分表
对于nginx实现轮询,权重方式?
对于轮询方式实现负载均衡,就是nginx默认的轮询算法,在配置文件中加入后台服务器。
对于权重方式实现负载均衡,就是在配置文件中加入后台服务器,应为后台服务器设置权重。
对于Redis你怎么看?
五大数据类型
事务
为什么快
持久化
自我介绍?
谈一谈你怎么使用git?
1、git基本操作
1、初始化仓库
新建git仓库
git init
克隆一个仓库
git clone <repository-url>
2、添加和提交
查看当前状态
git status
添加文件到缓存区
git add <file-name>
提交更改
git commit -m "Commit message"
3、查看历史记录
查看提交(简洁)历史
git log
git log --oneline
4、分支管理
新建分支
git branch <branch-name>
切换分支
git checkout <branch-name>
合并分支
git merge <branch-name>
删除分支
git branch -d <branch-name>
5、远程仓库
添加远程仓库
git remote add origin <repository-url>
推送本地分支到远程仓库
git push -u origin <branch-name>
从远程仓库拉取最新更改
git pull
6.保存当前工作目录而不提交
创建stash
git stash 或git stash save 带消息的
查看stash列表
git stash list
2、git高级操作
1、解决冲突
打开冲突文件,手动编辑解决冲突
编辑完成后,标记为已解决
git add <conflicted-file>
继续合并
git commit
2、回退提交
回退到上一个提交
git reset --hard HEAD-1
回退到特定的提交
git reset --hard <commit-hash>
3、暂存区管理
查看暂缓区和工作区的状态
git diff
撤销暂缓区的更改
git reset <file-name>
4、标签管理
创建标签
git tag <tag-name>
将标签发送到远程仓库
git push origin <tag-name>
状态码
200 OK
301 永久移除
302 临时重定向
400 请求语法有错误
401 请求未授权
403 服务器拒绝服务
404 请求资源不存在
500 服务器错误
503 服务器过一段时间恢复
项目中文件上传?
前端部分:
允许用户选择文件并提交,
这是一个form表单
enctype属性设置为multipart/form-data
methed属性设置为post
action属性设置为目标的URL 我这里是v1/upload
还有一个提交按钮,提交表单的内容
后端部分:
获取到这个文件
1、获取文件的名字
String fileOriginName = file.getOriginalFilename();
2、截取文件的后缀名
String suffix = fileOriginName.substring(fileOriginName.lastIndexOf('.'));
3、设置新文件名为uuid+文件后缀名
String newFileName = UUID.randomUUID()+suffix
4、自定义一个时间文件格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
String datePath = sdf.format(new Date());
5、创建文件路径
File fileDir = new File(FILE_PATH+datePath);
if(!fileDir.exists()){
fileDir.mkdirs();
}
//定义上传的位置
String filePutPath = FILE_PATH+datePath+newFileName;
6、上传文件
file.transferTo(new File(filePutPath));
7、将路径返回给前端
对于全局异常处理器?
对于ControllerAdvice注解:标识当前的类为全局异常处理器,可以处理由控制层抛出的异常
@RestControllerAdvice:复合注解 相当于@ResponseBody+@ControllerAdvice
1、如果Controller抛出了异常,首先看是否定义了全局异常处理器 2、若果定义了全局异常处理器就找到对应的异常处理方法 3、如果找到了对应的异常处理方法,则执行异常处理方法中的代码
在方法上加入@ExceptionHandle:表示方法为具体的异常处理方法,需要一个异常处理类型的形式参数
1、优先查找该控制器异常对应的处理方法 2、如果没有对应的异常处理方法,则会找父类的异常处理方法 3、如果父类的处理方法也没找到,则会走SpringMVC自己的异常处理机制
使用枚举类StatusCode定义自己的状态码及其对应的信息
1、SUCCESS 表示请求成功 200
2、NOT_LOGIN 表示用户未登录 1001
3、LOGIN_SUCCESS 表示为登录成功 201
4、PASSWORD_ERROR 密码错误 1002
5、USERNAME_ERROR 用户名错误 1003
6、USERNAME_ALREADY_EXIST 用户名已存在 1004
7、OPERATION_SUCCESS 操作成功 202
8、OPERATION_ERROR 操作失败 1005
9、VALIDATE_ERROR 表示为请求参数错误 1006
定义了一个JSONRESULT类用来封装API相应的结果,主要作用就是将业务处理逻辑的返回转化为JSON格式的数据便于响应给用户
1、code 内部状态码
2、msg 状态码描述的信息
3、data 具体的数据,业务返回的数据和错误信息
1、方法1 利用枚举类StatusCode返回状态码和描述
2、方法2 利用枚举类StatusCode返回状态码,描述,具体的数据
3、方法3 用来所有操作成功操作的生成对象
4、方法4 两个静态方法用于快速生成JSONRESULT对象
如何引入一个SpringSecurity框架?
1、添加SpringSecurity依赖
在pom.xml中添加SpringSecurity依赖
spring-boot-starter-security
2、配置SpringSecurity
创建一个配置类来配置springSecurity。
需要实现过滤器链SecurityFilterChain
权限设置http.authorizeRequests
允许注册和登录接口 .antMatchers("/v1/user/reg","/v1/user/login").permitAll()
其他所有请求都要认证 .anyRequests().authoriticated()
使用httpBasic认证 .httpBasic()
3、配置用户认证
实现UserDetailsService接口
使用user.getAuthorities
4、流程
@EnableWebSecurity启用了SpringSecurity
securityFilterChain方法定义了所有的安全性配置规则
userDetailsService 这个业务定义了一个用户的内存存储
passwordEncoder方法返回一个加密后的实例用于密码的加密和验证
BCrypt加密有加密强度和干扰因子 通过BCryptPasswordEncoder
对于java面试官问你还有什么想问我的?
1、公司使用哪些技术栈
2、关于团队,入职后分配到哪个团队
3、接下来的面试流程
实现多态的三种方式?
继承 接口 抽象
对于final
final int[] = {2,3,4};
arr[0] = 10;
system.out.println(arr[0]);
//输出为10 也就是说引用的指针不会改变,内容可以改变
对于String类concat方法的使用
String str1 = "hello";
str1.concat(" world");
String str2 = str1.concat(" world");
System.out.println(str1);// hello
System.out.println(str2);// hello world
forward和redirect的区别?
工作机制
forward:
转发:在服务器内部完成跳转,客户端浏览器不知道发生了跳转,URL的地址不变
请求共享:转发过程中,原始对象和响应对象传递到目标资源
性能:没有http请求,性能比较好
redirect:
客户端操作:重定向跳转,发送一个新的http请求来告诉浏览器去请求另一个URL,URL地址改变
请求不共享:新的请求是一个独立的请求,与原始数据无关,不能直接访问原始数据
性能:两次http请求,性能相对较低
String的方法有哪些?
字符串查询:
charAt(int index):返回指定索引的字符串
contains(CharSequenece s):判断是否包含指定的子字符串
endswith(String suffix):判断是否以指定的字符串结束
startsWith(String prefix):判断是否以指定的字符串开始
indexOf(int ch):返回指定的字符串第一次出现的位置
indexOf(String str):返回子字符串第一次出现的索引
lastIndexOf(int ch):返回指定字符串最后一次出现的索引
lastIndexOf(String str):返回指定子字符串最后一次出现的索引
toUpperCase():小写转大写
toLowerCase():大写转小写
字符串转换:
trim():去除两端的空白字符
replace(char oldStr,char newStr):新字符串代替老字符串
字符串分割:
split(String regex):根据正则表达式将字符串分割为数组
字符串格式化:
format():根据指定的字符串生成新的字符串
字符串比较:
equals(Object obj):判断两个字符串是否相等
equalsIgnoreCase():忽略大小写判断两个字符串是否相等
compareTo(String anotherString):比较两个字符串的字典顺序
子字符串提取:
substring(int beginIndex):从指定索引位置开始提取
substring(int beginIndex,int endIndex):指定开始指定结束
其他方法:
isEmpty():判断是否为空
isBlank():判断是否为空,空格不算
length():字符串长度
getBytes():将字符串转储为字节数组
join():字符串拼接
package com.yd.chll.day09;
public class Test6 {
public static void main(String[] args) {
String str = "Hello World";
System.out.println(str.charAt(2));
System.out.println(str.contains(" "));
System.out.println(str.endsWith("World"));
System.out.println(str.startsWith("Hello"));
System.out.println(str.indexOf(" "));
System.out.println(str.indexOf("orld"));
System.out.println(str.lastIndexOf("l"));
System.out.println(str.lastIndexOf("ll"));
System.out.println(str.toLowerCase());
System.out.println(str.toUpperCase());
System.out.println(str.trim());
System.out.println(str.replace("Hello", "Hello Hello"));
for (String string : str.split(" ")) {
System.out.print(string);
System.out.print(" ");
}
String format = String.format("123" + "456");
System.out.println(format);
String str1 = "hello";
String str2 = "hello";
String str3 = "Hello";
System.out.println(str1.equals(str2));
System.out.println(str1.equalsIgnoreCase(str3));
String str4 = "apple";
String str5 = "banana";
System.out.println(str5.compareTo(str4));
System.out.println(str.substring(3));
System.out.println(str.substring(0, 3));
String str6 = " ";
System.out.println(str6.length());
System.out.println(str6.isEmpty());
System.out.println(str6.isBlank());
System.out.println(str.length());
for (byte aByte : str.getBytes()) {
System.out.print(aByte + " ");
}
System.out.println();
System.out.println(String.join("apple ", "banana ", "orange"));
String str7 = "a";
byte bytes = str7.getBytes()[0];
System.out.println(bytes);
}
}
java中常见的关键字
修饰符
public protected private default
类和接口
class interface extends implements abstract final static synchronized transient volatile
控制流
if else for while do-while switch case default break continue return
异常处理
try catch finally throw throws
类型转换和对象操作
new instanceof
包和导入
package import
其他
this super void assert enum strictfp goto const
java中常见的运算符
算数运算符
加+ 减- 乘* 除/ 取余% ++自增 --自减
关系运算符
==等于 !=不等于 <小于 >大于 <= 小于等于 >=大于等于
逻辑运算符
&& 逻辑与AND ||逻辑或OR ! 逻辑非
赋值运算符
i++为先用后加 ++i先加后用
i+=1为 i=i+1
栈溢出是不是异常?
栈溢出是一种常见的运行时错误(StackOverflowError)是error的子类,表示一种严重的错误,优于递归调度太深或分配给线程的空间不足。
linux常用命令
文件和目录操作
-
ls
- 列出目录内容ls # 列出当前目录下的文件和目录 ls -l # 以长格式列出文件和目录 ls -a # 列出所有文件,包括隐藏文件 ls -lh # 以人类可读的格式列出文件大小
-
cd
- 改变当前工作目录cd /path/to/directory # 切换到指定目录 cd .. # 切换到上级目录 cd ~ # 切换到用户主目录 cd - # 切换到上次所在的目录
-
pwd
- 显示当前工作目录pwd
-
mkdir
- 创建目录mkdir directory_name # 创建单个目录 mkdir -p path/to/directory # 创建多级目录
-
rmdir
- 删除空目录rmdir directory_name # 删除单个空目录 rmdir -p path/to/directory # 删除多级空目录
-
rm
- 删除文件或目录rm file.txt # 删除文件 rm -r directory_name # 递归删除目录及其内容 rm -rf directory_name # 强制递归删除目录及其内容(谨慎使用)
-
cp
- 复制文件或目录cp file.txt newfile.txt # 复制文件 cp -r directory1 directory2 # 递归复制目录
-
mv
- 移动或重命名文件或目录mv file.txt newfile.txt # 重命名文件 mv file.txt /path/to/new/location # 移动文件 mv directory1 /path/to/new/location # 移动目录
文件查看和编辑
-
cat
- 查看文件内容cat file.txt # 显示文件内容 cat file1.txt file2.txt > combined.txt # 合并多个文件内容到一个新文件
-
less
- 分页查看文件内容less file.txt # 分页查看文件内容
-
head
- 查看文件开头部分head file.txt # 默认显示文件的前10行 head -n 5 file.txt # 显示文件的前5行
-
tail
- 查看文件结尾部tail file.txt # 默认显示文件的最后10行 tail -n 5 file.txt # 显示文件的最后5行 tail -f file.txt # 实时查看文件的新增内容
-
nano
- 简易文本编辑器nano file.txt # 编辑文件
-
vi
或vim
- 功能强大的文本编辑器vi file.txt # 编辑文件
文件权限和属性
-
chmod
- 更改文件权限chmod 755 file.txt # 设置文件权限为 rwxr-xr-x chmod u+x file.txt # 给文件所有者添加执行权限
-
chown
- 更改文件所有者chown user:group file.txt # 更改文件的所有者和组 chown user file.txt # 更改文件的所有者
-
stat
- 查看文件或文件系统的状态stat file.txt # 查看文件的状态
系统和进程管理
-
ps
- 显示当前进程状态ps aux # 显示所有进程的详细信息 ps -ef # 显示所有进程的详细信息
-
top
- 实时显示系统中各个进程的资源占用状况top
-
kill
- 终止进程kill PID # 终止指定PID的进程 kill -9 PID # 强制终止指定PID的进程
-
killall
- 终止所有同名的进程killall process_name # 终止所有名为process_name的进程
-
bg
和fg
- 控制后台和前台进程bg %1 # 将作业1放到后台继续运行 fg %1 # 将作业1放到前台继续运行
网络相关
-
ifconfig
- 显示或配置网络接口(在某些系统中已被ip
命令取代)ifconfig
-
ip
- 显示或操作路由、网络设备、接口等ip addr show # 显示网络接口的IP地址 ip link show # 显示网络接口的状态
-
ping
- 测试网络连接ping google.com # 测试与google.com的连接
-
netstat
- 显示网络状态netstat -tuln # 显示所有监听的TCP和UDP端口
-
curl
- 传输数据的工具curl http://example.com # 下载网页内容 curl -O http://example.com/file.zip # 下载文件并保存为原文件名
其他常用命令
-
grep
- 在文件中搜索文本grep "text" file.txt # 在file.txt中搜索包含"text"的行 grep -r "text" /path/to/directory # 递归搜索目录中的文件
-
find
- 搜索文件和目录find /path/to/directory -name "filename.txt" # 搜索名为filename.txt的文件 find /path/to/directory -type d # 搜索目录
-
tar
- 打包和解压文件tar -cvf archive.tar /path/to/directory # 创建tar归档文件 tar -xvf archive.tar # 解压tar归档文件 tar -czvf archive.tar.gz /path/to/directory # 创建gzip压缩的tar归档文件 tar -xzvf archive.tar.gz # 解压gzip压缩的tar归档文件
-
zip
和unzip
- 压缩和解压文件zip archive.zip file1.txt file2.txt # 压缩文件到archive.zip unzip archive.zip # 解压archive.zip
-
history
- 查看命令历史history # 查看命令历史
-
man
- 查看命令的手册页man ls # 查看ls命令的手册页
-
which
- 查找命令的路径which ls # 查找ls命令的路径
-
whereis
- 查找命令的二进制文件、源代码和手册页whereis ls # 查找ls命令的相关文件
试卷
重写父类的方法时,子类方法的修饰符级别要大于父类中方法的修饰级别
public >protected>default>private
类内部 同一个包 子类 其他包
构造方法不能有返回值 ,允许方法名相同,参数不同
抽象类可以有构造方法
方法的重载要求在参数列表不同:在同一个类当中,参数的个数,类型
命名要求:要求包括字母,数字,下划线,$符,不能以数字开头,严格区分大小写,不能使用关键字
字节流基类:InputStream OutputStream 字符流的基类:Reader Writer
String内容不可变 引用可变 有一些方法返回新的对象,不修改原来的对象
substring包含开始元素不包含结束的元素