JAVA基础
2021-06-29 12:00:32 23 举报
AI智能生成
JAVA基础
作者其他创作
大纲/内容
集合
List
ArrayList
数组
初始大小10,扩容系数1.5
查找时间复杂度O1
LinkedList
双向链表
不用进行扩容
查找时间复杂度On
Map
HashMap
数组大小必须是2的幂次方倍,因为取hash下标用的是hash&(size-1)
LinkedHashMap
实现跟hashmap差不多,但是给每个元素加了一个链表,每个元素会有一个指针指向下一个插入的元素。
使用linkedHashMap可以按插入顺序遍历
TreeMap
红黑树实现的
HashTable
线程安全的
在操作的时候对操作进行加锁。锁住整个结构
ConcurrentHashMap
只锁住当前桶,不影响其他桶
Set
跟Map差不多,只用到了map的key
HashSet
LinkHashSet
HashMap
hash算法优化(1.8以后)
实现
(h = key.hashCode())^(h>>>16)
把key原来的hash值和右移16位的hash值进行异或运算
把key原来的hash值和右移16位的hash值进行异或运算
相当于让它的高16位和低16位异或一下,自己本身的高16位还是一样的
右移16位
1111 1111 1111 1111 1111 1010 0111 1100
0000 0000 0000 0000 1111 1111 1111 1111
0000 0000 0000 0000 1111 1111 1111 1111
高16位易到低16位,然后前面补0
异或
不一样是1,一样是 0
1和0异或 是1
1111 1111 1111 1111 0000 0101 1000 0011
转换成int值
1111 1111 1111 1111 0000 0101 1000 0011 ->int
意义
如果两个差不多的值,他们的低16位相似,只有高16位有些差别,那么可能与算出来的值差不多
但是经过异或后,低16位就包含了高16位和低16位共同的特征,尽可能让更多的hash值低16位不一样,这样就让两个差不多的值就变得不一样了
但是经过异或后,低16位就包含了高16位和低16位共同的特征,尽可能让更多的hash值低16位不一样,这样就让两个差不多的值就变得不一样了
为的就是减少hash冲突的情况
寻址算法优化
(n-1)&hash =数组里的一个位置
数组长度-1 跟hash值做与运算
相当于高16位的运算是可以忽略的,因为数据的长度n都很小。核心在于低16位的与运算,相当于高16位没有参与到与运算里来
与运算
一样的是1,不一样的是0
为什么进行与运算,不取模
取模运算性能比较查一些,为了优化这个数组寻址的过程
hash&(n-1)->效果跟hash对n取模的效果是一样的,但是与运算的性能要比hash对n取模要高很多。
数学问题,数组的长度会一直是2的n次方,只要他保持数据长度是2的n次方,就可以满足 hash对n取模效果跟 hash&(n-1)效果一样
数学问题,数组的长度会一直是2的n次方,只要他保持数据长度是2的n次方,就可以满足 hash对n取模效果跟 hash&(n-1)效果一样
HashMap 解决hash碰撞
通过数组+链表+红黑树 O(n) O(logn)
HashMap如何扩容
默认2倍扩容
rehash
重新定位数组位置
CurrentHashMap
jdk1.7之前
分段加锁
每个数组对应一个锁
jdk1.8之后
锁粒度的细化
编程一个大的数组,数组里每个元素进行put操作,都有一个不同的锁,刚开始进行put的时候,如果两个线程都是在数组【5】这个位置进行put,这个时候,对数组【5】这个位置进行put的时候,采取的是CAS策略
通过对数组每个元素执行CAS的策略,如果很多线程对数据里不同的元素执行put,大家是没有关系的,如果其他人失败了,发现数组【5】这个位置已经有值了,那么就使用synchronized(数组【5】)锁进行链表或者红黑树进行处理
Spring
IOC
AOP
jdk动态代理和cglib动态代理的区别
jdk动态代理:在类有接口的时候就会来使用。
实现接口
cglib动态代理:类没有接口的时候。
生成类的子类,他可以动态生成子节码,覆盖你的一些方法,在方法里加入增强的代码。
spring中的bean是线程安全的么
spring的bean大部分都是单例的
答案是否定的,绝对不是线程安全的。都不是线程安全的。
一般来说在springbean里很少放实例变量。
事务
实现原理
如果说加了@Transactional注解,Spring就是使用AOP思想,对你这个方法在执行前,先去开启事务,执行完毕后,根据你方法是否报错,来决定回滚还是提交事务。
传播机制
REQUIRED
REQUIRED_NEW
NESTED
SpringBoot核心架构
1.内嵌Tomcat
2.自动装配
比如我们引入mybatis,其实主要引入一个starter依赖,他会一定程度上自动完成mybatis的一些配置和定义,不需要我们手工去做大量的配置了。
bean的生命周期
1.实例化Bean
2.设置对象属性(依赖注入)
这个bean依赖了哪个对象,就把依赖的bean也创建出来,进行注入。
3.处理Aware接口
如果Bean实现了ApplicationContextAware接口,spring容器就会调用我们的bean的setApplicationContext(ApplicationContext)方法,传入Spring上下文,把Spring容器传递给这个bean
把容器自己注入给bean,让bean能够拿到ApplicationContext
4.初始化前:BeanPostProcessor(postProcessBeforeInitialization)
如果我们想在bean实例构建好了以后并且依赖注入好,在这个时间点,我们如果想要对Bean进行一些自定义处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj,String s)方法。
5.初始化:InitializingBean与init-method:
如果Bean在Spring配置文件中配置了init-method属性,则会自动调用其配置的初始化方法
6.初始化后:BeanPostProcessor(postProcessAfterinitialization)
调用postProcessAfterinitialization(Object obj,String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
7.DisposableBean
当bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destory()方法;
8.destory-method
最后,如果这个Bean的Spring配置中配置了destory-method属性,会自动调用其配置的销毁方法。
设计模式
工厂模式
单例模式
代理模式
SpringMVC
1.http请求走到tomcat的工作线程,工作线程将其请求转交给spring mvc框架的DispatcherServlet
2.DispatcherServlet查找@Controller注解的controller,我们一般会给controller加上@RequestMapping的注解,标注说哪些controller用来处理哪些请求,此时根据请求的uri去定位到找哪个controller去处理。
3.根据RequestMapping去查找使用这个controller内的哪个方法来进行请求的处理,对每个方法一般也会加@RequestMapping的直接
4.它会直接调用controller里的某个方法来处理
5.处理完毕后,controller方法会有一个返回值。以前的时候,一般来说还是走jsp,模版技术。我们还是会把前端页面放在后端的工程里面,返回一个页面模版的名字,spring mvc的框架使用模版技术,对html做一个渲染。但是现在一般前后端分离,返回一个json串,可能前段发送一个请求过来,我们只要返回json数据。
6.再把渲染以后的html页面返回给浏览器去进行显示。前端负责把html页面渲染给浏览器就可以了。
网络
TCP三次握手和四次挥手
tcp建立连接的三次握手
第一次握手
客户端发送连接请求报文,此时SYN=1,ACK=0,seq=x,说明这是个连接请求
接着客户端处于SYN_SENT状态,等待服务器响应
第二次握手
服务端收到SYN=1的请求报文,需要返回一个确认报文TCP包,ack = x+1,SYN = 1,ACK = 1,seq = y,发送给客户端
自己处于SYN_SENT状态。
第三次握手
客户端返回ack = y+1,ACK=1,seq=x+1
为什么是三次
如果是2次
客户端发送第一次握手卡在半路上没过去
客户端发现没有相应,就又发了一次握手,然后返回了一次握手。连接建立。互相传送数据后连接断开
结果第一次卡在半路的握手到了服务端
服务器直接返回第二次握手,开辟了资源准备通信。
客户端收到第二次握手,但是已经处理完了,就导致服务端干等着。
但是如果三次握手,客户端发现第二次握手不是它想要的,第三次握手就直接让服务端释放资源,复位连接。
为啥不是四次五次
浪费资源
tcp断开连接的四次挥手
第一次挥手
客户端发送报文,FIN=1,seq=u,此时进入FIN-WAIT-1状态。
第二次挥手
服务端收到报文,这时候进入CLOSE_WAIT(等待关闭)状态,返回一个报文,ACK=1,ack=u+1,seq=v。
告诉客户端收到请求,准备关闭
close_wait是为了确保残余的数据都发送完毕
客户端收到这个报文后,直接进入FIN-WAIT-2状态,此时客户端到服务端的连接就释放了。
第三次挥手
服务端再发送连接释放报文,FIN=1,ack=u+1,seq=w
所有残余数据都发完了,正式关掉
服务端进入LAST-ACK状态
第四次挥手
客户端收到连接释放报文之后,发应答报文
ACK=1,ack = w+1,seq = u+1
客户端进入TIME_WAIT状态,等待一会儿客户端进入CLOSED状态,服务端收到报文后,就进入CLOSED状态
确保对面收到最后一条报文,如果对面没收到还能收到没收到的反馈信息
确保在这次连接期间的报文都从网络中消失,确保下次新的连接不会出现旧连接残留的报文影响
TCP/IP协议:是一系列网络协议的总和,它定义了电子设备如何接入互联网以及数据之间如何相互传输。
TCP/IP协议中将网络分为四层
应用层
传输层
TCP处于传输层
网络层
链路层
物理层
HTTP原理
就是根据http协议封装一个http的请求,把http请求封装到应用层数据包里,再封装在tcp数据包里,再封装在ip数据包里,封装在以太网数据包里。如果过大,可能会拆成几个包。
走以太网协议+交换机->广播->网关->多个网关->转发到目标机器上->一层一层的拆包->http请求报文->传递给tomcat->spring mvc ->http相应->一样的路径回去。
HTTP版本
浏览器->网站,互相之间先是通过三次握手,建立一个连接,浏览器和网站服务器互相都给对方留出一部分资源,浏览器发起http请求->tcp->ip->以太网,到网站服务器上面去,服务器返回一个响应,关闭连接,四次挥手。释放掉浏览器和服务器各自给对方保留的一份资源
http1.0
互联网初期一个网页基本上都没什么图片,当时就是一些文字,一个网页就是一大坨文字
短连接
http1.0要指定keep-alive来开启持久连接。默认是短连接,就是浏览器每次请求都要重新建立一次tcp连接,完事了就释放tcp连接。早期的网页都很low,没啥东西,就一点文字,就用这个没问题。但是现在,一个网页打开之后,还要加载大量的图片,css,js,这就坑爹了。
http1.1
2000年以后,网页发展很迅猛,一个网页包含大量的css,js,图片等资源。比如一个网页,打开一个网页可能浏览器要对网站发送几十次请求。
http1.1默认开启持久连接,就是说,http打开一个网页之后,底层的tcp连接就保持着,不会立马断开,之后加载css,js之类的请求,都会基于这个tcp来走。http1.1还支持host头,也就可以支持虚拟主机,而且对断点续传有支持。
http2.0
支持多路复用,基于tcp连接并行发送多个请求以及接收相应,解决http1.1同一时间对同一个域名的请求有限制的问题。
二进制分帧:将传输数据拆分为更小的帧(数据包),frame(数据包,帧),提高了性能,实现了低延迟高吞吐
头部和数据分开发送
长连接
业内不是什么场景都要用到的
HTTPS
http传输是明文的不加密的
工作原理
1.浏览器把自己支持的加密规则发送给网站
2.网站从这套加密规则里选出来一套加密算法和hash算法,然后把自己的身份跟信息用证书的方式发回给浏览器,证书里有网站地址,加密公钥,证书颁发机构。
3.浏览器会验证证书的合法性,然后浏览器地址栏会出现一把小锁;接着浏览器生成一串随机数密码,然后用证书里的公钥去加密(非对称加密);用约定好的hash算法生成握手消息的hash值,然后用密码对消息进行加密,然后把所有的东西(消息(随机密码加密的),消息的hash值,私钥加密的消息)都发送给网站服务器,这块走的是对称加密
4.网站服务器,从消息里面取出来公钥加密的随机密码,然后用私钥解密取出密码,然后用密码解密浏览器发过来的握手消息,计算消息的hash值,并验证与浏览器发送过来的hash值是否一致,最后用密码加密一段握手消息,握手消息的hash值,发给服务器。
5.浏览器解密握手消息,对比hash值与传过来的是否一致。如果一致,握手就结束,之后所有的数据通信都会由之前浏览器生成的随机密码对称加密进行传输。
公钥私钥一般是RSA算法
对称加密一般是AES,RC4,hash就是MD5
用浏览器访问地址www.baidu.com是怎么运行的
假设给电脑设置了几个东西
ip地址:192.168.31.37
子网掩码:255.255.255.0
网关地址:192.168.31.1
DNS地址:8.8.8.8
ip地址:192.168.31.37
子网掩码:255.255.255.0
网关地址:192.168.31.1
DNS地址:8.8.8.8
浏览器打开www.baidu.com
这个时候找DNS服务器,DNS服务器解析域名后,返回一个ip地址,比如172.194.26.108.接着会判断两个ip地址是不是一个子网的,用子网掩码255.255.255.0,对两个ip地址二进制做与运算,拿到192.168.31.0和172.194.26.0,明显不是一个子网的。
那就得发送一个数据包给网关,其实就认为是我们的路由器吧,就是192.168.31.1,而且我们是可以拿到网关ip的mac地址的,现在我们从应用层出发,通过浏览器访问一个网站,是走应用层http协议的。
应用层:请求就会根据http协议,封装一个应用层的数据包,数据包里就放了http请求报文
请求方法+URL地址+http版本:比如 GET http://172.194.26.108/test HTTP/1.1
浏览器请求一个地址,先按照
请求头
Host:www.baidu.com
Proxy-Connection: keepAlive
User-Agent: Mozilla/5.0
Host:www.baidu.com
Proxy-Connection: keepAlive
User-Agent: Mozilla/5.0
请求体,json等
传输层:这个层是tcp协议,这个tcp协议会让你设置端口,发送方的端口随机挑选一个
0 条评论
下一页