java全集
2021-08-08 14:45:07 12 举报
AI智能生成
我的学习全路线,详细版本,正在补全,持续更新。。。
作者其他创作
大纲/内容
内功
八大数据结构
数组
最常用的数据结构,想象成在尺子上放绿豆,在指定位置放很容易找到,但是数组长度不容易改变
栈
先进后出,想象往桶里放东西,是不是先放进去的最后才能拿出来
队列
先进先出,此处想象排队,先排的人先走
链表
想象成链条,一个个的小锁链组成一条链表,中间可以岁随意取下一块,但是想找到指定位置的一块只能从头开始数
树
就是类似我们思维导图这种形式的父子节点之间的关系
一个父节点可能有一个或者不止一个子节点,也可能没有子节点
我们最长用到的就是二叉树
这里去了解一下红黑树,再关注一下hashmap的源码
散列表
无序数组中想要找到指定的值在哪很困难,只能自己一个个去比较
但是我们可以在放入的时候就进行一个哈希运算(通过给定的值,进行一次地址运算,得到一个下标),放在下标处
下次再取这个元素的时候,我们再进行哈希运算得到下标,直接访问
哈希冲突
问题描述
就是我们不同的元素进行哈希运算后得到的下标可能是一样的,就产生了哈希冲突
解决方法
方法很多,这里着重关注拉链法
数组 + 链表
我们的数组存储的是链表节点
产生冲突时,把后来的元素挂在这个链表后面就可以了,这是尾插法
也可以插在链表头部,这叫头插法
堆
分为大顶堆、小顶堆
图
迪杰斯特拉算法
七大查找算法
十大排序算法
刷题
牛客-剑指offer
力扣-all
各个大厂模拟题
面经遇到的题
设计模式
内功需要持续修炼,并且很早就需要修炼,直到自身十分强大也不能丢弃
前端
祖传三大件
html
css
js
UI框架
LayUI
ElementUI
必看框架
Vue
后端
Java EE
尚硅谷Java全集跟完,你就知道什么是Java了
常见问题
八大基本数据类型
字节型
char
2字节、16位
布尔型
boolean
1字节、8位,但是只有1位有效,另外7位置0
整型
byte
1字节、8位
short
2字节、16位
int
4字节、32位
long
8字节、64位
浮点型
float
4字节、32位
double
8字节、64位
“==”和 equals 的区别
“==”
基本数据类型就是比较值
引用数据类型就是比较地址
equals
本质上就是“==”
有些类重写了equals方法,像String、Integer等,就是比较值了
为什么重写equals,必须重写hashcode
因为euqals判断的是对象是否相等,如果对象相等,那么他们的hashcode也应该相等
但是hashcode原本是通过地址计算的,所以我们要进行重写
hashcode相等,euqals一定相等吗?
不一定
散列表中,hashcode相等发生哈希冲突,equals不相等
final的作用
修饰变量
必须初始化,且值不能更改
修饰方法
被修饰的方法不能被重写
修饰类
被修饰的类不能被继承
String str = new String("abc"); 创建了几个对象
如果之前在常量池中已经存在abc,那么只创建一个对象
如果常量池中不存在abc,那么就是两个对象,因为jvm会先检查我们的常量池中是否存在abc,不存在会先创建
字符串类型对象
不可变字符串
String
可变字符串
StringBuffer
线程安全,效率低
StringBulider
线程不安全,效率高
字符串反转
StringBuffer、StringBulider的reverse()方法
BIO、NIO、AIO
BIO
同步阻塞IO
NIO
同步非阻塞IO
IO多路复用
多个socket链接,一个线程处理
通过channel频道实现多路复用
阻塞的不再是socket进程,而是系统调用
系统调用
select
poll
epoll
AIO
异步非阻塞IO
基于事件和回调机制实现
迭代器
在遍历集合元素并进行操作时,可能会引发ConcurrentModificationException异常
这是由于底层进行操作的时候会记录一个modCount和当前的Count,而进行删除操作会引发当前Count不等于modCount,引发异常
所以需要使用迭代器进行操作
创建线程的方式
继承Thread类,重写run方法
实现Runnable接口,实现run方法,用Thread包装
实现Callable接口,实现call方法,用FutureTask包装Callable对象实现执行结果返回,最后再用Thread包装
线程池创建线程
sleep和wait的区别
sleep来自Thread类,而wait来自Object类
sleep不释放锁,而wait释放锁
sleep到时间自动恢复,而wait可以通过notify、notifyAll提前唤醒
web开发
tomcat
整体架构
简介
Server是顶层容器,代表整个服务器,包含多个Service
每个Service包含**多个Connector**和**一个Container**,对外提供服务
每个Connector负责连接相关的事情,提供socket与Request和Response相关转换
Container用于封装和管理Servlet,以及具体处理Request请求
架构关系
Connector
Endpoint
监听socket通道,将socket接收到的数据转发给Processor
Processor
接收并解析来自Endpoint的http请求,封装成Request转发给Adapter
Adapter
接受来自Processor的Request对象,并把Request对象封装成ServletRequest,转发给Container,这里用到了**门面模式**
Container
Engine
一个Service只有一个Engine
Host
一个Engine可以有很多个虚拟主机(Host)
Context
每个Host又可以有很多个web程序(Context)
Wrapper
每个Context又对应很多个Servlet(Wrapper),Wrapper作为最底层的容器,不再有子容器
启动流程
点击startup.bat启动tomcat,这个批处理命令会去找catalina.bat
在catalina.bat中做了一件事,就是去找Bootstrap的main方法
那为什么要一个文件一个文件找呢?为什么不直接打开Bootstrap的main方法呢?
其实我抽取出来的重点是找到Bootstrap的main方法,但是中途有很多的系统验证,比如是否安装jdk等等,其中涉及的变量还是很多的
进入到BootStrap的main方法后,首先加上一个同步锁,再执行init初始化方法
init方法中,通过反射创建Catalina实例,并设置成守护线程
然后执行load加载方法,这个load方法执行完后,从server、service一直到context都被初始化完成了,这里是个嵌套的关系
执行完load方法后,执行start方法,再从server、service到ProtocolHandler都执行start方法,和上面一样,是嵌套关系
这里面同时还涉及到一个线程池的创建和初始化,这个操作紧跟在Service后面,Engine前面
请求流程
Connector阶段
Endpoint的NIOEndpointAcceptor监听socket端口,接受到请求,将请求转发给Processor
Processor将接受到的socket请求封装成Request对象
因为Container接受的是HttpRequest,而不是Request,所以adaptor的实现类coyoteAdapter会把Quest对象封装成HttpRequest,转交给Comtainer,这里设计到门面模式,其实就是进行了对象封装
这个接受请求转发给Container的整体实现有两种,一种是基于ajp实现的potocolHandler,一种是基于http1.1实现的protocolHander
Container阶段
Engine、Host、Context、Warpper都有标准的实现类,名字叫做StandardXXX
在请求传递过程中,会出现一个管道机制,它由pipeline和valve组成
这个其实就相当于一个拦截器,请求在每层容器传递过程中都要进行一些该层容器的处理,再交给下层的子级容器
管道通常由一个基础阀和若干普通阀组成,基础阀就是在该级容器和下层容器间建设桥梁,起到传递的作用,而普通阀就是用来做逻辑处理的
这里涉及到了责任链模式,在每层容器中都可以通过getPipeline得到管道对象,再由getFirst().invoke()执行第一个阀门逻辑,然后通过getNext().invoke()执行下个阀门逻辑
最终会到达相对于的servlet执行具体的doGet、doPost方法,然后返回结果
tomcat打破双亲委派机制
什么是双亲委派机制
加载过程从下到上寻找,再从上到下加载
BootStrapClassLoader
ExtensionClassLoader
ApplicationClassLoader
用户自定义的ClassLoader
为什么需要双亲委派机制
这是为了防止java核心类被篡改
常见问题
为什么使用线程池
如果没有线程池的话,每个请求到来的时候都会去开启一个线程对请求进行处理,若果一瞬间打来了上千个请求,会瞬间开启很多线程,直接就会导致服务器宕机,但是线程池在请求过多的时候会把暂时无法处理的请求存储在等待队列中,再者,线程池还有饱和策略应对请求过多的情况
另外就算请求量没有很高,每个请求来了还是得申请线程处理,线程线程完毕后立即销毁,不断的请求打过来,就会不断的重复这个过程,会给系统带来巨大的性能开销,我看过linux对于线程销毁的处理,线程的销毁并不是立刻销毁的,而是批量回收的,这个回收的过程会占用cpu资源,影响其他线程的运行,所以我们应该减少线程的销毁这一操作,线程池的线程的run方法是死循环的,它会不断的从队列中取任务执行,而不被销毁,这就减少了线程销毁这一操作带来的性能消耗,大幅提高了多线的的性能
void类型的doGet()和doPost()怎么返回数据
我们发起http请求,tomcat就接受到请求会封装两个对象,一个是request,一个是response
request就是我们的请求,会转发给相对应的servlet,然后处理的结果会保存在respoonse中,由tomcat把response转换成流,再通过tomcat返回给前端
SSM框架
spring
springmvc
mybatis
其他框架
springboot
mybatis-plus
数据库
MySQL
存储引擎
索引
事务
MVCC
explain分析
sql执行过程
慢查询优化
Redis
简介
基本数据类型
数据过期
事务
持久化
主从复制
哨兵模式
缓存穿透
缓存击穿
缓存雪崩
布隆过滤器
分布式锁
Linux
常用命令
目录
切换
进入当前目录的XXX目录
cd XXX
进入根目录
cd /
进入上级目录
cd ../
查看
查看当前目录和文件
ls
查看当前目录和文件以及隐藏文件
ls -a
创建
mkdir
删除
删除
rm XXX
递归删除
rm -r
递归不询问删除
rm -rf
修改
重命名aaa为bbb
mv aaa bbb
剪贴aaa到home
mv aaa /home
拷贝aaa到home
cp -r aaa /home
修改文件
进入xxx文件
vim xxx
开启编辑模式
i
退出编辑模式
ESC
保存并退出
:wq
撤销操作,退出
:q!
权限修改
chmod rwx
打包和解压缩
打包
tar -zcvf xxx.bar [xxx.txt........]
解压
tar -zxvf xxx.tar
进程相关
查看当前进程
ps -ef
带管道符的过滤查看
ps -ef | grep xxx
杀死进程
kill -9 pid
切换用户
su
sudo
查看当前路径
pwd
端口开放
查看当前端口开放情况
firewall-cmd --list-ports
打开某个端口
firewall-cmd --pernament --add-port=8888/tcp
关闭某个端口
firewall-cmd --permanent --remove-port=8888/tcp
重启防火墙
无success提示
systemctl restart firewalld
有success提示
firewall-cmd --reload
JVM虚拟机
点击链接移步
并发编程
点击链接移步
计算机网络
OSI七层模型
应用层
视图层
会话层
传输层
网络层
数据链路层
物理层
TCP/IP四层模型
应用层
传输层
网际层
网络接口层
TCP、UDP区别
面向连接
tcp面向有连接的服务
udp面向无连接的服务
传输单元
tcp以字节为单位进行传输
udp以报文为单位进行传输
可靠与否
tcp是可靠的传输服务
udp是不可靠的传输服务
传输速度
tcp传输速度慢
udp传输速度快
TCP如何实现可靠传输
传输前后数据是否发生变化
校验和机制(CRC循环冗余码)
传输过程是否丢失数据
序列号应答机制
丢失数据怎么办?
超时/重传机制
序列号应答导致传输效率低
滑动窗口机制
网络拥塞怎么办
拥塞控制
TCP连接的三握四挥
访问一个网站的全过程
HTTP的各个版本及特性
cookie、session
存储位置
session存储在服务器
cookie存储在浏览器
关系
session生成同时会有一个sessionID,会存储在cookie中,用户请求带着cookie,服务器就能拿到sessionID,就可以访问用户session
如果浏览器禁用cookie,还可以使用session吗?
可以的
只需要在url后面拼接sessionID就行了
HTTP如何保存用户状态
HTTP、HTTPS区别
分布式开发
RPC
简介
原理
Dubbo(相关框架)
springcloud
zookeeper
消息队列
简介
kafka(常用框架)
0 条评论
下一页