每日一问
2022-06-21 setter & getter
- setter 和 gettter 的实际意义
-
为什么要有setter & getter, public dot直接使用不是更方便快捷吗? 而且setter和getter最终的效果也是读写
- 安全:程序可以选择只读或只写或读写
- 灵活:如果不仅仅只是读写属性值,可以自由变换
- 封装:隐藏内部实现细节
- 健壮:便于维护,扩展
-
由上一问,为什么public是不安全的呢?
- 如果写sdk的话,那么有些数据是不想对外修改的,这时候public的作用就体现出来了。如果只是业务代码则,权限体现的不太大。
-
扩展:Java的四大特性 - 直接粘贴
封装
What:隐藏信息,保护数据访问。
How:暴露有限接口和属性,需要编程语言提供访问控制的语法。
Why:提高代码可维护性;降低接口复杂度,提高类的易用性。
抽象
What: 隐藏具体实现,使用者只需关心功能,无需关心实现。
How: 通过接口类或者抽象类实现,特殊语法机制非必须。
Why: 提高代码的扩展性、维护性;降低复杂度,减少细节负担。
继承
What: 表示 is-a 关系,分为单继承和多继承。
How: 需要编程语言提供特殊语法机制。例如 Java 的 “extends”,C++ 的 “:” 。
Why: 解决代码复用问题。
多态
What: 子类替换父类,在运行时调用子类的实现。
How: 需要编程语言提供特殊的语法机制。比如继承、接口类、duck-typing。
Why: 提高代码扩展性和复用性。
2022-06-22 编译&反编译
编译:源码 -> 字节码 反编译:字节码 -> 源码
什么是字节码,采用字节码的好处是什么?
在 Java 中,JVM 可以理解的代码就叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机。Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比较高效,而且,由于字节码并不针对一种特定的机器,因此,Java 程序无须重新编译便可在多种不同操作系统的计算机上运行。
2022-06-23 为什么String不可变
什么是不可变
一旦对象被创建并初始化后,内部的状态数据就会保持不变
为什么String不可变
- 最初的设计就是不可变,设计就是遵循一定的规则,基本约定,体现一致性。
- final和immutable无关
- 如果String可变,那么String就可以在方法之前来回穿梭,最终变成什么无人可知。
- 安全性:String作为hashmap的key值的时候,如果发生改变,则很难被发现
- 无线程安全问题
- 所以声明String为final一劳永逸
2022-06-25 为什么不应该通过类实例访问静态成员
如果使用类的实例来访问静态成员的话,那么IDEA会WARNING,那为什么会有这个WARNING呢?
查了一下网上的说明,模糊不清的说法是实例会被回收。
引申问题1 - 静态为什么叫静态?
静态变量 -> 类变量 是继承类的 所有对象共有的 非静态变量 -> 实例变量 具体对象的具体数据 根据对象的变化而变化 是继承对象的
引申问题2 - 什么时候可以定义静态变量或者方法?
所有的类都拥有的共同的属性 -> 静态变量
方法内部没有使用到非静态数据 -> 静态方法
引申知识点
-
静态的特点
- 通过类的加载而加载 类一旦被加载进内存,静态的变量和方法就被加载进去了,对象还不存在
- 静态先于对象存在
- 被所有的对象共享
- 可以直接被类名调用,也可以被对象调用
-
静态使用的注意事项
- 静态方法只能访问静态成员,不能访问非静态成员
- 非静态成员可以访问静态成员,也可以访问非静态成员
- 静态方法中不能出现this,super等关键字
-
静态的好处和坏处
- 优点:对于所有对象都共有的数据,节省空间;可以不新建对象直接使用;
- 缺点:静态是通过类存在的,访问存在局限性,只能访问静态数据
2022-06-29 HashMap
数据结构
数组(每个Node叫做bucket) + 链表 + 红黑树
主体是一个数组,数组由一个个链表组成,链表由一个个Node组成,Node存储具体的key value
为什么要使用数组+链表的数据结构
解决hash冲突,首先使用hash(key)得出key的hash值,然后通过 (n-1) & hash 得出index,键值对存在该index所在的数组链表中。
不同的key可能产生相同的hash值
- 如何解决Hash冲突
遇到hash冲突后,会先判断两个key值是否相同,相同说明是同一个key,则覆盖。如果不相同,会将这个Node插入链表的尾部。
- 头插法和尾插法
头插法:每次在头部插入,作者认为后面插入的使用的概率会更大,会造成死锁的问题 尾插法:每次在尾部插入,JDK1.8后更新
为什么要把链表转换为红黑树?
- 查找效率
链表:时间复杂度O(n) 红黑树:时间复杂度O(log(n))
链表较短的时候差距不大,较长的时候可以提升效率
- 为什么不直接使用红黑树的数据结构
红黑树的空间复杂度是链表的2倍
2022-06-30 反射
反射是什么?
反射可以在运行时检查类、接口、方法和变量等信息,无需知道类的名字,方法名等。还可以在运行时实例化新对象,调用方法以及设置和获取变量值。
2022-07-04 - 07-05 红黑树
6.29日看了hashmap的原理,那么红黑树到底是什么呢?
二叉查找树 BST(Binary Search Tree)
任何一个节点的左子树上的点,都必须小于当前节点。 任何一个节点的右子树上的点,都必须大于当前节点。 任何一颗子树,也都满足上面两个条件。
2-3-4树
4阶的B树,Balance Tree
所有的叶子节点都拥有相同的深度 叶节点只能是2-节点、3-节点、4-节点 元素使用保持排序顺序,父节点大于左子节点,小于右子节点,如果节点有多个元素,则每个元素必须大于它左边的和它左子树中的元素
2022-07-07
为什么https协议调用接口需要SSL认证
- SSL: Secure Sockets Layer, 安全套接字层,为了解决HTTP协议是明文,避免传输的数据被窃取,篡改,劫持。
- TSL: Transport Layer Security, 传输层安全协议。TSL是SSL标准化的产物。
- HTTPS: 兼容HTTP,HTTP over TSL,HTTPS = HTTP + TSL
总之,就是为了安全
Java里面怎么做?
- 如果是Resttemplate的话需要跳过,具体代码如下, 在RestTemplateConfig中加入下面代码:
|
|
- X509Certificate
X.509是公钥基础设施(PKI)的标准格式。X.509证书就是基于国际电信联盟(ITU)制定的X.509标准的数字证书。
2022-07-11
@Controller & @RestController
@ResponseBody
该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。使用此注解此次请求将不再走视图处理器,而是直接将此响应结果写入到输入流中,其效果等同于使用response对象输出指定格式的数据。
@Controller @Service @Compoent
spring在启动时,有一个非常核心的类ConfigurationClassPostProcessor会对类路径下的所以类进行扫描,将符合条件的bean扫描出来添加到beanDefinitionMap集合中,方便接下来的实例化。
@Controller
如果不使用springMVC时,三者使用其实是没有什么差别的,但如果使用了springMVC,@Controller就被赋予了特殊的含义。
spring会遍历上面扫描出来的所有bean,过滤出那些添加了注解@Controller的bean,将Controller中所有添加了注解@RequestMapping的方法解析出来封装成RequestMappingInfo存储到RequestMappingHandlerMapping中的mappingRegistry。后续请求到达时,会从mappingRegistry中查找能够处理该请求的方法。
@RestController
@Controller + @ResponseBody
2022-07-15
net.sf.ezmorph.bean.MorphDynaBean是什么?
net.sf.json就是一个类似于fastjson的一个json解析框架,这个库有点老了,现在应该没有人推荐了,所以其实今天这个问题就没必要记录了。但是还是看一下这个问题。
2022-07-27
2022-07-28
依赖的版本不一致
一般都是因为自定义版本导致的,而有些依赖会使用spring中写好的版本,所以一般这种情况就更改spring定制的版本号即可,更改就是重新写个全局版本号,会覆盖掉之前的。
2022-07-29 设计模式六大基本原则
单一职责原则 Single Responsibility Principle
There should never be more than one reason for a class to change。应该有且仅有一个原因引起类的变更。
意思也很明显,一个类应该有且只有一个引起它变化的原因。
实际案例: 手机Class V1:MobileClass, 包含了所有功能,charge(), ringUp(), GPU(), CPU(), RAM(), ROM() V2: BasicProperty, GPU(), CPU(), RAM(), ROM(); BasicFunction, charge(), ringUp() V3: BasicProperty, GPU(), CPU(), RAM(), ROM(); ExtendProperty(), Pixel(); BasicFunction, charge(), ringUp(); ExtendFunction, playGame();
没有最好的设计,只有最适合的设计。
2022-07-30 设计模式六大基本原则
里氏替换原则 Liskov Substitution Principle
子类对象能够替换父类对象,而程序逻辑不变。
有两种情况,使用共享方法或者是为了多态。
- 共享方法:子类继承父类为了方法重用,则子类不应该去改变父类中的共享方法。子类和父类都可以实例化,如果子类复写父类的共享类,则违反了LSP,子类对象不能够替换父类对象,逻辑有可能不一致。
- 多态:如果继承为了多态,则应该将父类方法设为抽象类或者接口,这样子类重新定义父类的方法,父类不能实例化,替换的时候不会造成逻辑上的不一致。
如何符合LSP:尽量不要从可实例化的父类中继承,而是要使用基于抽象类和接口的继承。
2022-07-31
多态
2023-04-10 三次握手
重启每日一问的问题,同步更新微信
首先先明确一下三次握手的流程:
shake hands1: client send [SYN, SEQ=X] -> server
shake hands2: server send [SYN, ACK=X+1, SEQ=Y] -> client
shake hands3: client send [ACK=Y+1, SEQ=Z] -> server
接下来开始使用wireshark进行抓包,查看抓包中的交互信息,下面以www.baidu.com为目标进行抓包。通过ping查看www.baidu.com的真正ip为110.242.68.4,通过wireshark的过滤条件src host 110.242.68.4 or dst host 110.242.68.4 来过滤数据包。
Shake hands 1
可以看到前三个请求都为TCP的请求,就是我们所说的握手过程,只有在握手之后才能进行真正的http的请求。
可以看到第一次握手中客户端源端口61539向服务器目标端口443端口进行SYN的请求,SYN=1,ACK=0表示连接请求报文段。
Shake hands 2
在第二次握手的时候可以看到SYN=1,ACK=1表示服务器同意客户端的连接请求。我们也可以看到seq+1。
Shake hands 3
第三次握手,客户端发送ACK=1给服务端,此时TCP连接成功,开始发送和接收数据。
2023-04-11 四次挥手
上面的三次握手学完之后,相信对整个TCP的连接和wireshark的使用有了基本的了解。下面简单看一下四次挥手的过程即可。
four waves 1: client send [FIN, ACK, Seq=X, ACK=Y] to server
four waves 2: server send [ACK, Seq=Y, Ack=X+1] to client
four waves 3: server send [FIN, ACK, Seq=Z, Ack=X+1] to client
four waves 4: client send [ACK, Seq=X+1, Ack=Z+1] to server
2023-04-13 IOC - Inversion of Control
资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处。第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。
2023-04-14 Nginx 配置项
- tcp_nodelay
Nagle Algorithm: John Nagle的名字来命名的,John Nagle在1984年首次用这个算法来尝试解决福特汽车公司的网络拥塞问题(RFC 896)。如果每次发送一个1 byte的数据包,实际大小需要40(20ip header bytes + 20 tcp header bytes) + 1 byte = 41bytes,Nagle算法解决了该问题,如果包的大小满足MSS,那么可以立即发送,否则放入缓冲区,等到已经发送的包被确认了之后继续发送。
DelayedAcknowledgment: 如果需要单独确认每个包的大小的话,那么整个网络当中将充斥着无数的ACK,降低网络性能,DelayedAcknowledgment规定: 不再针对单个包发送ACK确认,而是一次确认两个包,或者在发送相应数据的时候捎带这发送ACK,又或者出发超时时间后再发送ACK。
上述的两个解决网络性能问题的方法如果在一起使用,会触发延迟问题,如果TCP client端启用了Nagle Algorithm, Server启用 Delayed ACK,并且发送的数据包比较小,Client端需要等待Server端对上一个packet的Ack才能发送当前Packet,Server延迟发送Ack,那整个通信将会被延迟。
- 数据量小,交互多的情况需禁用Nagle算法和Delay,TCP_NODELAY: on
- 数据量大,交互少需要开启,这种情况典型的应用是文件服务器
- 仅长连接使用
- tcp_nopush
tcp_nopush就是开启linux中的TCP_CORK(塞子), 类似于在发送数据管道处插一个cork,阻塞所有数据,直到取消cork,全部发送阻塞数据。
tcp_nopush和sendfile一起使用。
- sendfile
正常网络文件传输过程:
file -> 硬盘 -> kernel buffer -> user buffer -> kernel socket buffer -> 协议栈
senfile网络文件传输过程:
file -> 硬盘 -> kernel buffer(快速拷贝到kernel socket buffer) -> 协议栈
性能提升
- lua_shared_dict access 10m