腾讯微信事业部的一面。问的不是很难,希望能有戏吧
这次的面试流程比上次的面试要更加干脆和快速。直接上来就给我问题目了。那么我们这次也直接进入正题吧。
## 1、分别介绍一下OOP的三大特征
这是老生常谈的问题了。但是感觉这次自己还是没有把这个概念给解释清楚。这次就让我自己用文字把这三个东西解释清楚吧。
### 封装性
封装性就是把客观事物抽象成类,并且只让自己可信任的类或者对象操作自己的数据和方法(通过访问限制符限定),对不可信的信息隐藏。以防止程序中无关的部分意外地改变或者错误地使用了对象的私有部分。
例子:
比如打电话,我们只需要知道怎么样拨打电话即可(如何操作类),而不需要知道手机的内部结构,便于使用(防止被破坏)
### 继承性
继承是类与类之间的一种关系,是“Is a”的关系。java中的继承是单继承,一个类只能有一个父类。
继承的好处在于,子类拥有父类的所有属性和方法(除了private),从而一定程度上实现了代码的复用。同时如果继承的父类方法不适合或者不满意,可以重写方法。同时,也可以基于父类的方法扩展出新的方法,从而扩展了代码的能力
### 多态性
多态就是指对象的多种形态。就是指一个类实例的相同方法在不同情形有不同表现形式。父类既可以指向自己的对象也可以指向子类的对象是一种多态。在某些时候,可以把子类当作父类来看,屏蔽不同子类之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
注意:我在面试的时候提到了重写和重载。这里一定要注意区分啊!
+ 重载(Overloading):==指同一个类中的多个方法==具有相同的名字,但这些方法具有不同的参数列表,即参数的数量或者参数类型不能完全相同(签名不同)
+ 重写(Override):==是指存在父子关系之间的==,子类定义的方法和父类中的方法具有星通的方法名字,相同的参数列表和返回类型,但是中间的代码逻辑是不一致的。注意重写的时候子类的方法的限制符不能小于父类(不能比父类有更小的可见性)
## 2、大小端存储
大端模式,是指将数据的高字节保存在内存的低地址当中,而数据的低字节保存在内存的高地址当中。如保存0x12345678的话,两种模式的存储情况如下:
内存地址 | 小端 | 大端
---|---|---
0x4000 | 0x78 | 0x12
0x4001 | 0x56 | 0x34
0x4002 | 0x34 | 0x56
0x4003 | 0x12 | 0x78
**总结一下:这个“端”一定指的是低地址的那个地方。大端的意思就是高位存储在低字节(大的先),小端指的就是低位存储在低字节(小的先)**
大端的话,如果按照内存地址的顺序读下去,顺序就是像字符串一样是正确的。如上例,将数据直接取出就是0x12345678
## 3、线程安全
这个也是老生常谈的问题了。自己去看中科创达面试的解释吧。就懒得复制黏贴啦~
## 4、线程通信/进程通信
说了一些,但是不全
### 进程之间的通信
+ 管道:速度慢,容量有限,**只有父子进程能通讯**
+ 有名管道:任何进程都可以通讯(估计是注册在共享存储区的),但是速度慢
+ 消息队列:容量受到系统限制,且要注意第一次读的时候要考虑上一次没有读完数据的问题
+ 信号量:不能传递复杂消息,只能用来同步
+ 共享内存:能够控制容量,速度快,但是要保持同步。这个方法可以用做线程间通讯,但是没有必要,因为线程本身就已经共享了同一进程内的一块内存
### 线程间通信
+ 共享变量:**注意处理同步**
+ 管道通信
## 5、线程之间和进程之间访问的数据是一样的吗?
不是的。线程之间访问的同一个进程下的共享数据块,而进程之间可以访问的是系统里面的一个共享存储区
## 6、线程和进程的概念
进程:进程是具有独立功能的程序在某个数据集合上的一次执行过程。进程是系统进行资源分配和调度的一个独立单位。
线程:线程是进程内的一个执行实体或者执行单元,是比进程更小的、能够独立运行的基本单位。
区别:
不同进程的地址空间相互独立,而同一进程内部的线程共享同一地址空间。一个进程内部的线程对另外一个进程是不可见的。
创建进程和撤销进程,系统都要为之分配或者回收资源,操作系统的开销远大于创建和撤销线程。
## 7、局部变量是存在栈还是堆,对象又是在栈还是堆?
局部变量存在于栈中。
除此之外,栈还存放类的引用、方法的引用、操作数、方法出口等
使用new新建的对象存在于堆中。而使用static中new的对象又是存在哪的呢?
## 8、事件驱动模式
自己回顾一下自己的博文吧:[学习Unity3D时对事件驱动模式的理解](https://blog.csdn.net/csc1998/article/details/81435252)
## 9、TCP/UDP的区别?
### TCP
##### 优点
可靠,稳定 TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源
##### 缺点
慢,效率低,占用系统资源高,易被攻击。TCP在传递数据之前,要先建连接,这会消耗时间,而且在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,事实上,每个连接都会占用系统的CPU、内存等硬件资源。 而且,因为TCP有确认机制、三次握手机制,这些也导致TCP容易被人利用,实现DOS、DDOS、CC等攻击。
### UDP
##### 优点
快,比TCP稍安全。UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议,所以它在传递数据时非常快。没有TCP的这些机制,UDP较TCP被攻击者利用的漏洞就要少一些。
##### 缺点
不可靠,不稳定 因为UDP没有TCP那些可靠的机制,在数据传递时,如果网络质量不好,就会很容易丢包。
### 总结
区别 | TCP | UDP
---|---|---
是否基于连接 | 是 | 否
系统资源耗费 | 较多 | 少
结构 | 较复杂 | 简单
模式 | 流模式 | 数据报模式
丢包 | 否 | 是
数据顺序 | 保证 | 不保证
## 10、非对称加密
非对称加密算法是一种密钥的保密方法。
非对称加密算法需要两个密钥:公开密钥(public key)和私有密钥(private key)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。
## 11、搭建TCP的步骤(接口调用)
看自己的 NIO学习笔记
## 12、内存泄漏和内存越界
这个他问的内存泄漏,但是我一开始回答成内存越界了。
这里再把两个概念搞清楚一点
1. 内存泄漏:
内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
在java中,具体的情况是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放
比如说长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。
2. 内存越界:
内存溢出就是指在指定大小的内存空间,写入了超出大小的数据(越界).或者没有足够的内存,供程序分配。
## 12、滑动窗口协议
参考:
> [Java面试--网络基础(OSI模型/TCP与UDP/滑动窗口协议)](https://blog.csdn.net/jianghao233/article/details/82756539)
> [TCP协议-滑动窗口、拆包和粘包](https://blog.csdn.net/jjavaboy/article/details/80037057)
作用:维持发送方和接收方的缓冲区
缓冲区的用途:解决网络传输不可靠的问题,如丢包、重包、包出错等;提高确认重传机制的效率;平衡发送方和接收方处理数据的能力
### 发送端滑动窗口
1. Sent and Acknowledged(已发送且确认)——窗口外
数据已经传输给接收端并且收到ACK,这部分已经在窗口之外,表示已经传输成功。
2. Send But Not Yet Acknowledged(已发送未确认)
发送方已经送出但是没有收到接收端ACK,这部分是处于窗口内的,被认为是还未完成发送的信息
3. Not Sent,Recipient Ready to Receive(未发送但有能力接收)
这部分是发送方还没有发送,但是是处于接收端告知发送端的可接受的数据范围内的,应该就尽快发出
4. Not Sent,Recipient Not Ready to Receive(未发送且没有能力接收)——窗口外
超出接收端范围,这部分不处于窗口内,等待未来窗口滑动进入并发送的。
接收方会从两种方式告知发送方他的发送窗口范围:
+ TCP三次握手时
+ 在接受过程中,回传ACK时(ACK包会包括希望接收的下一字节和允许接收的字长)
### 接收方滑动窗口
1. Received and ACK Not Send to Process(接收并确认但未交付)
接收到了发送端的数据,并且已经回传了ACK,但是还没有交付给上层应用,这部分是在窗口内的
2. Received Not ACK(接收未确认)
接收到了数据但是没有回传ACK,可能的原因是数据包乱序抵达等
3. Not Received(未接收)
接收方有能力接收,但是没有数据到达的空闲位置
## 拆包和粘包
> 参考: [TCP粘包,拆包及解决方法](https://blog.csdn.net/wxy941011/article/details/80428470)
拆包和粘包是一个新的问题呢。是TCP基于字节流所带来的一些问题
UDP是基于报文发送的,从UDP的帧结构可以看出,在UDP首部采用了16bit来指示UDP数据报文的长度。这样的话,在传输层交付给应用层的时候,应用可以很好地区分数据包,所以UDP不存在拆包和粘包的问题。
而TCP是基于字节流发送的,TCP把从应用层传下来的数据看作一串无结构的字节流,没有边界。此外,TCP的帧结构中,首部没有表示数据长度的字段。所以在TCP中可能存在拆包和粘包的现象发生。
拆包和粘包有两种情况,图来自参考链接。
情况一:粘包
![image](https://img-blog.csdn.net/20180524001857215?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d4eTk0MTAxMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
情况二:拆包和粘包
![image](https://img-blog.csdn.net/20180524001917767?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d4eTk0MTAxMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
### 发生拆包和粘包的原因:
拆包:
+ 要发送的数据大于TCP发送缓冲区(窗口)的大小,就会发生拆包
+ 待发送数据大于MSS(最大报文长度),TCP在传输前将拆包
粘包:
+ 要发送的数据小于TCP发送缓冲区,TCP将多个包写入同一个缓冲区一并发送出去,将会产生粘包(如果窗口大小小于两个包数据总和的大小,最后一个包还会发生拆包)
+ 接收端的应用层没有及时读取缓冲区数据,后续数据包到达粘在缓冲区内的包后,将会产生粘包
### 解决方案
+ 发送端给每个数据包添加包首部,首部中至少包含了数据包长度。这样接收方就和UDP一样知道一个数据包的长度了。
+ 发送端将每个数据包封装为固定长度(不够的可以通过0填充)。这样接收方就可以按照固定长度拆分数据包
+ 可以在数据包之间设置边界,如添加特殊符号等。接收方可以检测分隔符进而拆分数据包
【实习面经】腾讯 WXG 零面总结