2018面试笔记

JAVA

  • Collection

    List(有序,可重复) 底层实现 特点 线程安全
    ArrayList 数组 查询快,增删慢,效率高 NO
    Vector 数组 查询快,增删慢,效率低 YES
    LinkedList 链表 查询慢,增删快,效率高
    Set(无序,唯一) 底层实现 特点 线程安全
    HashSet 哈希表 依赖两个方法:hashCode()和equals() NO
    LinkedHashSet 链表和哈希表组成 链表保证元素有序,由哈希表保证元素唯一 NO
    TreeSet 红黑树 接受Comparator的实现类对象自定义排序 NO
    Map 底层实现 特点 线程安全
    HashMap 哈希表 效率高 NO
    LinkedHashMap 链表和哈希表 元素有序唯一 NO
    HashTable 哈希表 效率低 YES
    TreeMap 红黑树 接受Comparator对象自定义排序 NO
    • HashMap中Entry链太长,查找的时间复杂度可能达到O(n),怎么优化
    • jdk1.8中,采用了新的红黑树的结构来实现,当链表的数量大于8的时,就会将冲突的节点保存在红黑树里。
    • ConcurrentHashMap与HashTable比较
    • ConcurrentHashMap采用的锁分段技术,能更好的并发性能,读取对象的时候 ConcurrentHashMap 并不会把整个 Map 锁住,只是把 Map 中正在被写入的部分进行锁定。
    • ConcurrentHashMap读操作并不需要加锁。

    • JAVA中AIO/BIO/NIO

    • BIO:Bloking IO (同步,阻塞IO):当调用线程时会一直等待数据操作完成。
    • NIO:Non-bloking IO (同步,非阻塞IO):调用线程时,会一直判断是否建立连接,没有话则回到主线程继续执行其他代码。
    • AIO:Asynchronous IO (异步,非阻塞IO。称为NIO2,jdk1.7+):调用线程,直接回到主线程。
  • JAVA Direct Memory

    • 在java NIO类中引入Channel与BUffer的IO方式,它可以直接通过native函数直接分配堆外内存,通过堆中的DirectByterBuffer对象引用这块内存进行操作,这样避免了java堆和native堆中来回复制数据。
  • JVM

    • JVM内存结构
    • 程序计数器:选取下一条指令,分支,循环,异常,跳转,线程恢复。
    • 方法区:类信息,常量,静态变量,编译后数据。
      • 常量池:new String()是在堆中建立对象,String s = “”是直接放在常量池中,String的intern()将对象放进常量池中。
    • 堆:存放对象实例,堆划分:新生代和老年代。
    • 栈:函数的实现
    • 垃圾对象判断算法
    • 引用计数算法:应用计数器。
    • 可达性分析算法:从GC root开始搜素,当一个对象到GCroot没有任何连接,则对象不可用。
      • 第一次标记,是否执行finalize()(该方法只执行一次),如果执行过或者没有覆盖finalize()则不执行。第二次才会真正回收。
    • 回收算法
    • 标记-清除:产生内存碎片。
    • 复制算法:将内存分成Eden和2个Survivor(TO From)空间(8:1),将存活对象复制到另一个TO Survivor中,清空Eden和(From)Survivor。
    • 标记-整理:清理后进行内存碎片整理。
    • 分代收集:在新生代中使用复制算法,在老年代中使用标记-整理或者标记-清除算法。
    • GC STW(stop the world):可达性分析确保一致性,必须暂停所有线程,一般在full-GC会出现STW。
    • GC种类
    • G1(最新):适合新生代和老年代,采用标记-整理算法。
    • CMS:标记-清除算法,老年代。
    • 减少GC开销措施:
    • 不要显式调用System.gc()
    • 减少临时对象的使用
    • 使用StringBuffer,而不用String来累加字符串
    • 能用基本类型如Int,Long,就不用Integer,Long对象
    • 尽量少用静态对象变量:静态变量属于全局变量,不会被GC回收,它们会一直占用内存
  • 类加载机制
    • 类加载过程:

2018面试笔记
- 加载:获取类的二进制字节流动作。
- 验证:检查class文件数据的正确性。
- 准备:给静态变量分配存储空间,并初始化为0。(变量是static final)则赋值。
- 解析:将符号引用转为直接引用
- 初始化:对静态变量,静态代码快初始化操作。
- JAVA 线程
- volatile: 禁止指令重排;保证变量可见性。变量被volatile修饰后,线程修改变量后会立即被更新到主内存中,当其他线程读取变量会直接从主内存中读取
- 线程池

线程池 特点
newCachedThreadPool 工作线程的创建数量几乎没有限制(interger.MAX_VALUE)。空闲时间默认1min,则终止改线程。
newFixedThreadPool 指定工作线程数量,超过则提交到池队列中。不会释放空闲线程。
newSingleThreadExecutor 只创建一个工作线程执行任务,按FIFO执行
newScheduleThreadPool 指定工作线程数量,支持定时及周期性任务执行

- Thread 类中的start() 和 run() 方法有什么区别
- start()方法被用来启动新创建的线程,而且start()内部调用了run()方法。调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。
- Java中什么是竞态条件
- 多线程对一些资源的竞争的时候就会产生竞态条件,如果首先要执行的程序竞争失败排到后面执行了,那么整个程序就会出现一些不确定的bugs。这种bugs很难发现而且会重复出现,因为线程间的随机竞争。

C++

  • 虚函数表
    • 虚函数的作用主要是实现了多态的机制,虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)
  • 构造函数能不能是虚的, 为什么
    • 不能,vtable存储的是对象的内存空间,对象没有实例化,没有分配内存空间,因此建立vtable;vbtl在构造函数调用后才建立,因而构造函数不可能成为虚函数
  • 析构函数能否为虚,是否析构函数都要是虚的? 为什么?
    • 能为虚函数,当父类引用指向子类时,父类析构函数必须设为虚函数,这样当delete父类引用是,会先调用子类析构函数,在调用父类析构函数,否则会造成内存泄漏。
    • 其他情况不需要设为虚函数
  • C++多态是怎么实现的,虚函数相关知识
    • 在父类的函数前加上virtual关键字,在子类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。
  • 什么叫纯虚函数,纯虚类,虚函数
    • 纯虚函数:只有定义,没有实现,继承是必须实现纯虚函数
    • 虚函数:子类中可以被重写
    • 纯虚类,含有纯虚函数,不能实例化。java中抽象类。
  • 结构体和共同体的区别

    • struct和union都是由多个不同的数据类型成员组成, 但在任何同一时刻, union中只存放了一个被选中的成员, 而struct的所有成员都存在。
    • 在struct中,各成员都占有自己的内存空间,它们是同时存在的。一个struct变量的总长度等于所有成员长度之和。在Union中,所有成员不能同时占用它的内存空间,它们不能同时存在。
    • Union变量的长度等于最长的成员的长度。对于union的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于struct的不同成员赋值是互不影响的
  • static 和const分别怎么用,类里面static和const可以同时修饰成员函数吗

    • 当static用来修饰局部变量的时候,它就改变了局部变量的存储位置(从原来的栈中存放改为静态存储区)及其生命周期(局部静态变量在离开作用域之后,并没有被销毁,而是仍然驻留在内存当中,直到程序结束,只不过我们不能再对他进行访问),但未改变其作用域
    • static修饰全局变量,并未改变其存储位置及生命周期,而是改变了其作用域,使当前文件外的源文件无法访问该变量
    • 不可以同时用const和static修饰成员函数
  • const 函数
    • const函数不能修改成员变量,但是static变量可以修改
    • 加const和不加const表示不同的函数
    • const函数中不能调用非const函数,const对象只能调用const成员函数
    • 有mutable修饰的成员,仍然可以通过const成员函数修改
  • 指针和引用的区别,引用可以用常指针实现吗
    • 本质上的区别是,指针是一个新的变量,只是这个变量存储的是另一个变量的地址,我们通过访问这个地址来修改变量。
    • 引用只是一个别名,还是变量本身。对引用进行的任何操作就是对变量本身进行操作,因此以达到修改变量的目的。
  • Overload(重载):在C++程序中,可以将语义、功能相似的几个函数用同一个名字表示,但参数或返回值不同(包括类型、顺序不同),即函数重载。
    (1)相同的范围(在同一个类中);
    (2)函数名字相同;
    (3)参数不同;
    (4)virtual 关键字可有可无。
  • Override(覆盖):是指派生类函数覆盖基类函数,特征是:
    (1)不同的范围(分别位于派生类与基类);
    (2)函数名字相同;
    (3)参数相同;
    (4)基类函数必须有virtual 关键字。
    注:重写基类虚函数的时候,会自动转换这个函数为virtual函数,不管有没有加virtual,因此重写的时候不加virtual也是可以的,不过为了易读性,还是加上比较好。
  • Overwrite(重写):隐藏,是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
    (1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
    (2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

  • vector

    • 连续存储,随机访问方便
    • 但是插入元素时,需要移动的数目多,效率低
    • 所谓动态增加大小,并不是在原空间之后接续新空间(因为无法保证原空间之 后尚有可供配置的空间),而是以原大小的两倍另外配置一块较大的空间,然 后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间。 因此,对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭 代器就都失效了。
  • deque
    • 有vector所有功能外,还支持首端插入删除,是一个双向队列
  • list
    • 不连续内存,删除插入快,是双向循环链表
  • set
    • 不允许重复值,以红黑树实现,支持高效插入、删除等操作
  • multiset
    • 允许重复值,以红黑树实现,支持高效插入、删除等操作
  • map
    • 一对多映射,基于关键字快速查找,不允许重复值,以红黑树实现
  • multimap
    • 允许重复值,其他和map一样
  • stack : 栈
  • queue :队列
  • priority_queue:最高优先级元素总是第一个出列
    2018面试笔记

  • new与malloc的区别

    • new操作符从*存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存
    • new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。
    • new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL。
    • 使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸。
    • ew/delete会调用对象的构造函数/析构函数以完成对象的构造/析构。而malloc则不会。
    • operator new /operator delete的实现可以基于malloc,而malloc的实现不可以去调用new。
    • opeartor new /operator delete可以被重载
特征 new/delete malloc/free
分配内存的位置 *存储区
内存分配成功的返回值 完整类型指针 void*
内存分配失败的返回值 默认抛出异常 返回NULL
分配内存的大小 由编译器根据类型计算得出 必须显式指定字节数
处理数组 有处理数组的new版本new[] 需要用户计算数组的大小后进行内存分配
已分配内存的扩充 无法直观地处理 使用realloc简单完成
是否相互调用 可以,看具体的operator new/delete实现 不可调用new
分配内存时内存不足 客户能够指定处理函数或重新制定分配器 无法通过用户代码进行处理
函数重载 允许 不允许
构造函数与析构函数 调用 不调用

- #define和const的区别
- const 定义的常数是变量 也带类型, #define 定义的只是个常数 不带类型。
- define是在编译的预处理阶段起作用,而const是在 编译、运行的时候起作用。
- define只是简单的字符串替换,没有类型检查。而const有对应的数据类型,是要进行判断的,可以避免一些低级的错误。
- define占用代码段空间。 const,占用数据段空间
- const常量可以进行调试的,define是不能进行调试的,因为在预编译阶段就已经替换掉了
- define可以用来防止头文件重复引用,而const不能
c++常用知识点

计算机网络

  • 负载均衡

    • DNS:为同一个主机名配置多个映射,可采用轮训或随机。弊端:如果一台机器down机,则出现访问失败。
    • 负载均衡器:性能好,价格高,硬件负载均衡。
    • 反向代理:nginx,通过响应时间进行负载均衡。
    • CDN:内容分发网络,主要是存储静态文件,将CND节点分布在各个地区,根据用户请求地区,分配CDN服务器。
  • TCP和UDP的区别

    • TCP面向连接,UDP是无连接
    • TCP提供可靠的数据传输(无差错,无丢失,有序),UDP穿透性抢(尽最大努力交付),不可靠传输
    • TCP要求系统资源较多,UDP较少
    • UDP具有较好的实时性,工作效率比TCP高
    • TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
  • 长连接和短连接
    • 长连接:建立连接后一直保持连接
    • 短连接:建立连接传完数据后立马断开连接
  • OSI,TCP/IP 体系结构
    • OSI分层 (7层):物理层、数据链路层、网络层、传输层、会话层、表示层、应用层
    • TCP/IP分层(4层):网络接口层、 网际层、运输层、 应用层
    • 每一层的协议如下:
      • 物理层:RJ45、CLOCK、IEEE802.3 (中继器,集线器)
      • 数据链路:PPP、FR、HDLC、VLAN、MAC (网桥,交换机)
      • 网络层:IP、ICMP、ARP、RARP、OSPF、IPX、RIP、IGRP、 (路由器)
      • 传输层:TCP、UDP、SPX
      • 会话层:NFS、SQL、NETBIOS、RPC
      • 表示层:JPEG、MPEG、ASII
      • 应用层:FTP、DNS、Telnet、SMTP、HTTP、WWW、NFS
    • 每一层的作用如下:
    • 物理层:通过媒介传输比特,确定机械及电气规范(比特Bit)
    • 数据链路层:将比特组装成帧和点到点的传递(帧Frame)
    • 网络层:负责数据包从源到宿的传递和网际互连(包PackeT)
    • 传输层:提供端到端的可靠报文传递和错误恢复(段Segment)
    • 会话层:建立、管理和终止会话(会话协议数据单元SPDU)
    • 表示层:对数据进行翻译、加密和压缩(表示协议数据单元PPDU)
    • 应用层:允许访问OSI环境的手段(应用协议数据单元APDU)
    • 协议介绍
    • ARP地址解析协议,转换IP地址到MAC地址
    • NAT协议:网络地址转换属接入广域网(WAN)技术,是一种将私有(保留)地址转化为合法IP地址的转换技术
    • DHCP协议:一个局域网的网络协议,使用UDP协议工作,用途:给内部网络或网络服务供应商自动分配IP地址,给用户或者内部网络管理员作为对所有计算机作*管理的手段
  • TCP怎么保证错误重传
    • 接收方收到错误的分组,就直接丢弃,而不做任何操作
    • 发送方在规定的时间(比平均往返时延大一些)没有收到分组的确认分组,就会自动重传
    • 分组编了序号
  • UDP模拟TCP
    • TCP协议将需要发送的数据分割成数据块。数据块大小是通过MSS(maximum segment size)来控制的,这种机制是一种协商机制,MSS规定了传往接收方的最大数据块的大小。MSS通过SYN报文协商的,若接收方不接受来自另一方的MSS值,则MSS就定为一个固定值。MSS值越大,网络的利用率越高。
    • 重传。设置定时器,等待确认包。
    • 对首部和数据进行校验。
    • TCP对收到的数据进行排序,然后交给应用层。
    • TCP的接收端丢弃重复的数据。
    • 流量控制。(通过每一端声明的窗口大小来提供的)
    • UDP协议,可以发送的最大的字段多大?
    • 2^16 - 20 -8 = 64k
    • TCP time_wait状态
    • time_wait状态是主动关闭方在发送四次挥手的最后一个ACK会变为TIME_WAIT状态,保留次状态的时间为两个MSL(linux里一个MSL为30s,是不可配置的)。
    • 可靠的终止连接,当client发给server的ack丢失,server再次发送fin文段,client必须处于可接受状态。
    • TIME_WAIT关闭的危害:
      • 网络情况不好时,如果主动方无TIME_WAIT等待,关闭前个连接后,主动方与被动方又建立起新的TCP连接,这时被动方重传或延时过来的FIN包过来后会直接影响新的TCP连接;
      • 同样网络情况不好并且无TIME_WAIT等待,关闭连接后无新连接,当接收到被动方重传或延迟的FIN包后,会给被动方回一个RST包,可能会影响被动方其它的服务连接。
  • POST和GET区别
    • GET方法向URL添加数据;URL的长度是受限制的(URL 的最大长度是 2048 个字符)。POST无限制
    • GET请求只能进行url编码,而POST支持多种编码方式
    • GET能被缓存,POST不能缓存
    • GET产生一个TCP数据包;POST产生两个TCP数据包,GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
  • Ping的底层协议
    • ICPM协议:它是一种差错和控制报文协议,不仅用于传输差错报文,还传输控制报文
  • Traceroute:首先给目的主机发送一个TTL=1的UDP数据包,而经过的第一个路由器收到这个数据包以后,就自动把TTL减1,而TTL变为0以后,路由器就把这个包给抛弃了,并同时产生 一个主机不可达的ICMP数据报给主机。主机收到这个数据报以后再发一个TTL=2的UDP数据报给目的主机,然后刺激第二个路由器给主机发ICMP数据报

  • 拥塞控制算法

    • 慢开始:建立连接时,拥塞窗口设置为1,设置慢开始门限,每收到ACK,拥塞窗口加1倍,拥塞窗口呈指数增长。
    • 拥塞避免:当拥塞窗口达到门限值时,则没收到一个ACK,拥塞窗口加1个,拥塞窗口呈现行增长。
    • 快重传:求接收方收到一个失序的报文段后就立即进行重复确认,如果接收方一连收到三个重复的ACK,那么发送方不必等待重传计时器到期,立即重传。
    • 快恢复:当连续收到3个重复ACK,则将拥塞窗口减半,并执行拥塞避免算法

操作系统

  • 进程通信有哪些方式?
    • 管道:只能用于具有亲缘关系的进行通信,使用面相对较窄,实际开发中较少使用;
    • FIFO(命名管道):可以用于任意进程间的通信,对于大块数据的传输效率较高,可应用于单进程大量数据传递,和多个进程向一个进程传递数据;
    • 信号:无法传递数据,而且信号的种类有限,只适用于完成一些简单的事件通知任务,如配置跟新信号通知,一个服务通过信号告知另一个服务自身状态;
    • 文件锁:不能用来传递数据,用来对操作进行协调,利用文件锁实现多个进程对于某个资源的排队请求,或者多个进程对系统某个全局资源进行读写操作,可以通过文件锁实现进程间读写锁的功能;
    • 共享内存:最为高效的进程间通信方式,进程可以直接读写内存,不需要任何数据拷贝,适用于多个进程共享数据,或进程间频繁的进行大量的数据交互;–建议使用mmap方式;
    • 消息队列:进程间传递简单的命令和控制消息,如配置更新通知,多进程对多进程的通信等,可以简化代码逻辑;–建议使用全双工管道替代;
    • 信号量:某种资源数为N,多个进程都在使用该资源,为了进行进程间的互斥,可以使用初始值为N的信号量;–建议使用记录锁替代;
    • unix域套接字:某个服务与多个服务同时通信,此时需要维护多个通信通道,使用unix套接字,可以使用linux IO多路复用功能;–建议优先考虑网络套接字;
    • 网络套接字:如果系统需要支持分布式部署,服务可能在同一设备或者不同设备,此时使用网络套接字比较合适,提高了扩展性。

Kubernetes Docker

架构

2018面试笔记

Kubernetes核心组件

  • Master

    • API Server :资源对象操作入口,所有组件必须通过它提供的API操作资源
    • Scheduler :收集和分析当前Kubernetes集群中所有Minion节点的资源(内存、CPU)负载情况,然后依此分发新建的Pod到Kubernetes集群中可用的节点。
    • Controller Manager :负责集群内的Node、Pod副本、命名空间(Namespace)、服务账号(ServiceAccount)、资源定额(ResourceQuota)等管理,并执行自动修复流程,确保集群处于预期状态。
      • Replication Controller :确保集群中RC所关联的Pod副本数始终保持预设值,调整RC中的spec.replicas属性值来实现系统扩容或缩容,改变RC中的Pod模板来实现系统的滚动升级
      • Node Controller :kubelet在启动时会通过API Server注册自身的节点信息,并定时向API Server汇报状态信息,Node Controller通过API Server实时获取Node的相关信息,实现管理和监控集群中的各个Node节点的相关控制功能
      • ResourceQuota Controller :资源配额管理确保指定的资源对象在任何时候都不会超量占用系统物理资源
      • 容器级别:对CPU和Memory进行限制
      • Pod级别:对一个Pod内所有容器的可用资源进行限制
      • Namespace级别
    • etcd :分布式数据库,保存整个集群状态
  • Minion

    • Kubelet:负责Node节点上pod的创建、修改、监控、删除等全生命周期的管理,定时上报本Node的状态信息给API Server,通过cAdvisor监控检点和容器资源
    • Kube-proxy:负载均衡,路由转发(Proxy不但解决了同一主宿机相同服务端口冲突的问题,还提供了Service转发服务端口对外提供服务的能力,Proxy后端使用了随机、轮循负载均衡算法)
    • Pod:k8s资源调度的最小单位

Static Pod

  • 以非API server创建的Pod称为Static Pod。Kubelet将static Pod状态汇报给API server,API Server 为该Static Pod 创建一个 Mirror Pod 和其相匹配,Mirror Pod 的状态将真实反映 Static Pod 的状态,当 Static Pod 被删除时,与
    之相对应的 Mirror Pod 也会被删除

其他组件

  • kube-dns:负责为整个集群提供 DNS 服务
  • Ingress Controller: 为服务提供外网入口
  • Heapster: 提供资源监控
  • Dashboard: 提供 GUI
  • Federation: 提供跨可用区的集群
  • Fluentd-elasticsearch: 提供集群日志采集、存储与查询

Kubernets资源调度

  • Scheduler分为两个阶段:Predicates(预选)阶段和Priorities(优选)阶段,predicates阶段是判断有没有主机符合pod资源(port,资源,磁盘空间,selector,hostname),如果指定了NodeName或者是静态Pod则Scheduler不参与调度。

  • Priorities阶段:判断哪一个主机最适合运行Pod,有以下调度策略

    • LeastRequestedPriority(最少请求资源优先调度策略)
    • ServiceSpreadingPriority(最小相同服务优先调度策略)
    • EqualPriority(平等优先调度策略)
    • BalanceResourceAllocation(拥有类似内存和CPU使用的节点)

Kubernetes概念

  • namespace:一组资源和对象的集合。(node,pv则不属于任何namespace)
  • Service:自动分配一个cluster IP和DNS名,通过labels为应用提供负载均衡和服务发现。
  • Lable:对象的标签,可以通过lable selector来选择label的对象

Docker 网络模式

  • Bridge(默认模式): 容器连接到Docker0虚拟网桥上,以Docker0 IP作为网关,给容器分配子网。
  • Host:容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace,使用宿主机IP和端口
  • Container:定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡
  • None:使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置

Docker 与虚拟机区别

  • Docker 容器共享主机系统内核,虚拟机则需要虚拟硬件,内核。
  • Docker 使用Linux namespace 隔离容器运行环境,cgroups限制容器使用资源

精简Docker 镜像

  • 减少镜像层,Dockerfile中每条指令都会创建一个镜像层,将多个linux命令放在一个指令中执行。
  • 对镜像中安装包进行clean all

机器学习十大算法

  • 朴素贝叶斯
    • 用途:分类
    • 定理:贝叶斯定理
    • 前提条件:假设特征条件独立(各个特征之间互不相干)