问题 | 答案 |
---|---|
java 1.7 1.8 1.9 新特性 参考: https://www.cnblogs.com/aspirant/p/8617201.html 抽象方法不能有具体实现 | 1.7 在Switch中可以用String字符串 ;二进制变量的表示,支持将整数类型用二进制来表示,用0b开头;Catch多个异常;泛型实例的创建可以通过类型推断来简化 可以去掉后面new部分的泛型类型,只用<>就可以了;
1.8 接口里面可以有默认和静态方法;HashMap性能优化;Lambda 表达式;函数式接口;使用 :: 双冒号进行方法引用;Stream API; 默认方法:可以有具体实现,”类优先”原则,冲突则重写原则 静态方法:接口的静态方法属于接口本身,不被继承,也需要提供方法的实现 λ表达式本质上是一个匿名方法 : (x, y) -> { return x + y; } λ表达式有三部分组成:参数列表,箭头(->),以及一个表达式或语句块 函数式接口:是个接口,只能有一个抽象方法,但能有多个非抽象方法
1.9 JShell 交互式编程;集合工厂方法;改进的Stream API; |
java4种引用 强弱软虚 java.lang.ref 与引用密切相关的,还有一个引用队列ReferenceQueue | 强引用:垃圾回收器绝不会回收它 如 Object obj = new Object()
软引用(SoftReference):可有可无,内存空间足够,就不会回收它,如果内存空间不足了,就会回收 用来实现内存敏感的高速缓 ,和引用队列(ReferenceQueue)联合使用
弱引用(WeakReference):可有可无,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。Weak引用对象会更容易、更快被GC回收
虚引用(PhantomReference):用来跟踪对象被垃圾回收器回收的活动,虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 联合使用。回收器发现对象还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列。(无法通过虚引用取得实例,不会对生存时间构成影响,垃圾回收时收到一个系统通知) |
java 类加载顺序 | 父类 静态变量/静态代码块 (看二者在代码中的先后顺序) 子类 静态变量/静态代码块 父类 普通变量/普通代码块 (看二者在代码中的先后顺序) 父类 构造函数 子类 普通变量/普通代码块 (看二者在代码中的先后顺序) 子类 构造函数 |
介绍Java反射 | java程序在运行时能够获取类的所有信息
实现原理: Class类(类类型):保存运行时类型信息,没有公共构造方法,每个类都有一个Class对象,某个类的Class对象被载入内存,它就用来创建这个类的所有对象。
Class类获取方式:String.class object.getClass() Class.forName("Object")
Class对象获取方式: 无参 String s = (String) c.newInstance() 有参只能通过构造器获取 类构造器获取:Constructor getConstructors() con.setAccessible(true); //设置可访问的权限 类的成员变量:Field getFields() 类的方法:Method getMethods() m.invoke() |
介绍java泛型 泛型类在内存上只有一个 泛型擦除:成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。 | 什么是泛型:将类型由原来的具体的类型参数化,类型定义成参数形式,使用时传入具体类型。
使用泛型的好处: 编译器负责类型安全检查,将类型检查从运行时挪到编译时;消除强制类型转换;
泛型类: 父类定义的类型参数不能被子类继承 紧跟类命之后的<>内,指定一个或多个类型参数的名字 List <E,V> 指定上限 <T extends Number> 下限<? super Number>
泛型方法:是否拥有泛型方法,与其所在的类是否是泛型没有关系。 范围修饰(例如public)之后的<>内,指定一个或多个类型参数的名字 public <T> void print(T t)
泛型接口:interface Inter<T>
通配符?(类型参数赋予不确定值)类型通配符一般是使用 ? 代替具体的类型实参 |
注解 参考: https://blog.youkuaiyun.com/hla199106/article/details/47319447 | 元数据,即一种描述数据的数据,注解会被编译至class文件中 分类:JDK内置系统注解、元注解、自定义注解
元注解的作用就是负责注解其他注解 : @Target(被描述的注解可以用在什么地方) @Retention(注解在什么范围内有) @Documented (将注解包含在Javadoc中)@Inherited(允许子类继承父类中的注解)
@Retention用于提示注解被保留多长时间 : SOURCE 保留在源码级别,被编译器抛弃(@Override就是此类);CLASS被编译器保留在编译后的类文件级别,但是被虚拟机丢弃;RUNTIME保留至运行时,可以被反射读取。 注解处理器类库(java.lang.reflect.AnnotatedElement) |
String、StringBuilder、StringBuffer | String : final 修饰的类,不可变 StringBuilder:可变字符数组,默认初始化大小16,调用构造方法添加字符串后会自动扩容16,线程不安全,扩容为原容量2倍+2 StringBuffer :synchronized 关键字修饰,线程安全, |
java 异常 | Throwable又派生出Error类和Exception类。 错误:Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。因此,程序员应该关注Exception为父类的分支下的各种异常类。 异常:Exception以及他的子类,代表程序运行时发送的各种不期望发生的事件。可以被Java异常处理机制使用,是异常处理的核心 |
Java 动态代理 参考: https://blog.youkuaiyun.com/hla199106/article/details/46832143 | Proxy 提供代理类示例的获取
生成的代理类 $ProxyN 继承Proxy 实现传递的接口,被 final 和 public 修饰(注:只能为接口实现动态代理,因为已经继承了Proxy) InvocationHandler 提供代理类方法的执行
|
深拷贝 & 浅拷贝 | 是对 对象 进行拷贝,但对象里面存在 基本数据类型 和 引用数据类型 浅拷贝: 基本数据类型进行值传递,复制一份新值给新对象;引用数据类型(数组、对象)进行引用传递,成员变量的引用值(内存地址)复制一份给新的对象。 protected Object clone() 浅拷贝 无法直接使用 ,clone方法的类必须实现Cloneable接口,否则会抛出异常CloneNotSupportedException 要使用clone方法的类中重写clone()方法,通过super.clone()调用Object类中的原clone方法。
深拷贝:基本数据类型同浅拷贝;引用数据类型为所有引用数据类型的成员变量申请存储空间, 深拷贝的实现方法主要有两种: 1.每一层的每个对象都进行浅拷贝,每一层的每一个对象都实现Cloneable接口并重写clone方法, 2.通过对象序列化实现深拷贝 |
序列化 参考: https://blog.youkuaiyun.com/sanyaoxu_2/article/details/79722431 | 序列化(编码):将对象序列化为二进制形式(字节数组) 反序列化(解码):字节数组还原成原始对象 影响序列化性能的关键因素:序列化后的码流大小(网络带宽的占用);是否支持跨语言; 常见序列化协议: XML:当做配置文件存储数据;只能序列化公共属性和字段,不能序列化方法;文件庞大,文件格式复杂,传输占带宽; JSON:数据格式比较简单,序列化后数据较小;数据的描述性比XML差; Fastjson:接口简单易用,java语言中最快的json库;过于注重快,而偏离了“标准”及功能性,代码质量不高,文档不全; Thrift:序列化后的体积小, 速度快;对于数据字段的增删具有较强的兼容性;即文本(text)和二进制(binary)传输协议, Protobuf:通过代码生成工具可以生成对应数据结构的POJO对象和Protobuf相关的方法和属性 |
XSS 攻击 跨站脚本(cross site script)没完全过滤客户端提交的数据 参考: | 恶意攻击者利用网站没有对用户提交数据进行转义处理或者过滤不足的缺点,进而添加一些代码,嵌入到web页面中去。使别的用户访问都会执行相应的嵌入代码。从而盗取用户资料、利用用户身份进行某种动作或者对访问者进行病毒侵害的一种攻击方式。
1.反射型xss攻击 把我们的恶意脚本通过 URL 的方式传递给了服务器,而服务器则只是不加处理的把脚本“反射”回访问者的浏览器而使访问者的浏览器执行相应的脚本。 2.存储型xss攻击 例:留言板中加JS代码,存储到后端服务器,用户访问时执行 3.DOMBased攻击 例:通过交互修改浏览器页面中的DOM |
TCP 三次握手、四次挥手 | 三次握手目的:防止已失效的连接请求报文段突然又传送到了服务端 四次挥手目的:TCP 是全双工的,四次挥手是为了确保双方都没数据再传输了 |
TCP UDP | TCP 可靠、面向字节流的、面向连接的 传输层通讯协议。头部20字节
UDP 不可靠、面向数据包、无连接的 传输层通讯协议,尽最大努力交付 不保证有序传输。速度快,可支持广播。头部8字节 |
流量控制与拥塞控制 | 流量控制:是端到端的控制,例如A通过网络给B发数据,A发送的太快导致B没法接收(B缓冲窗口过小或者处理过慢),这时候的控制就是流量控制,原理是通过滑动窗口的大小改变来实现。
拥塞控制:是A与B之间的网络发生堵塞导致传输过慢或者丢包,来不及传输。防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不至于过载。拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络性能有关的所有因素。 |
TCP 拥塞控制 参考: https://blog.youkuaiyun.com/m0_37962600/article/details/79993310 | TCP拥塞控制:(防止过多的数据注入到网络当中 拥塞窗口:cwnd 慢开始门限:ssthresh) 慢开始:由小到大逐渐增大发送窗口只至达到最大 避免拥塞:拥塞窗口缓慢增大,例 加1 快重传:一条TCP连接有时会因为等待重传计时的超时而空闲较长时间,立刻发出重复确认,接收方一连收到三个重复的ACK,那么发送方不必等待重传计时器到期,由于发送方尽早重传未被确认的报文段 快恢复:连续收到三个重复确认时,执行“乘法减小”算法 |
UDP 拥塞控制 | UDP是一种无连接协议,在传输速度上占有一定优势,但它缺乏拥塞控制机制,传输可靠性差 UDP根据丢包率来判断网络的拥塞情况,若出现网络拥塞,接收方则通知控制方调整发送速率从而有效解决公平性问题和UDP的拥塞控制问题。 局部调整算法:根据接收方本次接收数据消息的序列号和前一次接收的差值得到丢包数(局部丢包数)来调整发送方的数据发送率 全局调整算法:根据接收方开始接收数据消息到本次接收消息结束这段时间内产生的丢包数(全局丢包数)来调整数据发送率 |
http & https | HTTP: 应用层协议,主要用于Web浏览器和Web服务器之间的数据交换 、无连接、无状态 工作原理: 地址解析 (分解出协议名、主机名、端口、对象路径等)、封装HTTP请求数据包、封装成TCP包,建立TCP连接(TCP的三次握手)、客户机发送请求命令、服务器响应、服务器关闭TCP连接
HTTPS:HTTP + SSL,工作在传输层。传输的数据都是加密后的数据 |
对称加密 非对称加密 参考: | 对称加密:一个密钥,用来加密和解密; 相关算法 : DES(数据加密标准) AES(高级加密标准) 非对称加密:两把密钥(公钥、私钥),公钥加密私钥解密或者私钥加密公钥解密; 相关算法 :RSA 加密速度慢。 中间人攻击:劫持公钥,修改公钥,得到浏览器密钥X(对称密钥) 解决办法:数字证书 数字证书: CA机构颁发,证书持有者、证书持有者的公钥 数字签名:防止数字证书被篡改, 数字证书MD5(私钥加密)+数字证书明文传输 浏览器验证过程:明文MD5与解密数字证书MD5比较 |
二叉搜索树(二叉排序树) AVL(自平衡二叉搜索树) 红黑树(自平衡二叉搜索树) | 二叉搜索树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值 AVL : AVL树中任何节点的两个子树的高度最大差别为1 红黑树:节点是红色或黑色;根节点是黑色;每个红色节点的两个子节点都是黑色;从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点 红黑树是弱平衡,左右子树高度差不一定为1,插入时调整次数比AVL少,适合插入频繁的查找操作。 |
同步、异步、阻塞、非阻塞 参考: | 同步和异步的概念:针对比如接口调用,服务调用,API类库调用等 同步:调用者必须要等待这个接口的磁盘读写或者网络通信的操作执行完毕了,调用者才能返回 异步:调用者调用接口之后,直接就返回了。接口通过回调函数、内部通信机制来通知 阻塞和非阻塞:针对的是底层IO操作 第一阶段:从网络中读取数据到kernel(数据准备阶段) 第二阶段:从kernel复制到user space (系统调用,必定是阻塞) 阻塞:数据准备阶段程序一直阻塞等待数据准备完成 非阻塞:数据准备阶段不会阻塞住,内核会返回一个异常消息给程序,程序可以干点别的,然后不断去轮询去访问内核 |
NIO 参考: | 核心部分组成 :Channels 、Buffer、Selector (还有Pipe、FileLock) Channel :从通道读取数据到缓冲区,从缓冲区写入数据到通道 FileChannel、SocketChannel、ServerSocketChannel
Buffer:可以写入数据、也可以从中读取数据的内存 写入数据到Buffer ,通过flip()方法将Buffer从写模式切换到读模式;从Buffer中读取数据,清空缓冲区:调用clear(清空所有)或compact(清空已读)方法 capacity :缓存容量 position : 写到哪、读到哪 limit :还有多少可写、还有多少可读
Selector:将channel注册到selector上,注册感兴趣事件 (Connect、Accept、read、write),注册成功返回 SelectionKey(包括 interest集合、ready集合、Channel和Selector) 通过Selector选择通道: select() :返回就绪事件通道个数 selectedKeys():返回注册的SelectionKey |
Reactor 参考: https://blog.youkuaiyun.com/qq924862077/article/details/81026740 | Reactor 就是基于NIO中实现IO多路复用模式 三种角色: Reactor 将I/O事件分派给对应的Handler Acceptor 处理客户端新连接,并分派请求到处理器链中,构建handler,绑定到相应的hanlder上 Handlers 执行非阻塞读/写 任务 单Reactor单线程模型:业务处理组件能快速完成的场景、不能充分利用多核资源 单Reactor多线程模型:获取到IO的读写事件之后,交由线程池来处理 多Reactor多线程模型:mainReactor负责监听server socket、subReactor维护自己的selector |
IO多路复用技术 select poll 用一个进程来处理多个fd的请求(检查数据是否准备好了) 适用于针对大量的io请求的情况 | 注: select 函数 与【阻塞/非阻塞IO】没任何关系
程序调用后select函数后会阻塞,直到有fd就绪或者超时、函数错误,才会返回,当select函数返回后,可以通过遍历fdset,来找到就绪的描述符。返回之后执行系统调用,将数据从kernel复制到进程缓冲区。
select 缺陷: 1.单个进程所打开的FD是有一定限制的,它由FD_SETSIZE设置,默认值是 32为机器 1024 64位机器2048 2.扫描时是线性扫描,即采用轮询的方法,效率较低。 3.每一次呼叫 select( ) 都需要先从 user space把 FD_SET复制到 kernel(因为会出现FD的变更所以每次都得复制),传递该结构时复制开销大
poll的原理与select非常相似,差别如下: 缺点是还是得有复制操作 1.基于链表来存储的,不存在没有最大连接数的限制 2.“水平触发”,通知程序fd就绪后,没有被处理,那么下次poll时会再次报告该fd |
事件驱动技术 epoll 支持 水平触发、边缘触发 参考: | poll_create(int size) 建立一个 epoll 对象,并传回它的id epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) 事件注册函数,将需要监听的事件和需要监听的fd交给epoll对象 epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) 等待注册的事件被触发或者timeout发生 边缘触发,它只告诉进程哪些fd刚刚变为就绪态,并且只会通知一次 使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。
1.没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口) 2.效率提升,不是轮询的方式,不会随着FD数目的增加效率下降 3.内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销 |
select poll epoll 对比 | 一个进程所能打开的最大连接数: select 1024 poll 无限制 epoll 1G内存 10W,2G内存 20W FD剧增后带来的IO效率问题: select 、poll 每次线性遍历性能低 epoll 只处理就绪的fd 消息传递方式:select 、poll 都需将fd从用户空间复制到内核 epoll 内核和用户空间共享
|
sendfile (零拷贝) 参考: https://blog.youkuaiyun.com/u013018618/article/details/80146617 | DMA 控制器 : Direct Memory Access,直接内存存取 图1 :传统方式读取数据后并通过网络发送 所发生的数据拷贝 图2:零拷贝-sendfile (减少了步骤2、3 cpu只需参与一次) 图 3:linux内核2.4以后,socket缓冲区做了调整,DMA带收集功能(数据的位置和长度的信息的描述符增加至内核空间(socket缓冲区)) ①一个read系统调用后,DMA执行了一次数据拷贝,从磁盘到内核空间 ②read结束后,发生第二次数据拷贝,由cpu将数据从内核空间拷贝至用户空间 ③send系统调用,cpu发生第三次数据拷贝,由cpu将数据从用户空间拷贝至内核空间(socket缓冲区) ④send系统调用结束后,DMA执行第四次数据拷贝,将数据从内核拷贝至协议引擎 ⑤另外,这四个过程中,每个过程都发生一次上下文切换 |
mmap | 使用mmap+write方式代替原来的read+write方式,mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系;
这样就可以省掉原来内核read缓冲区copy数据到用户缓冲区,但是还是需要内核read缓冲区将数据copy到内核socket缓冲区 |