JAVA面试复习知识点

面试中遇到的题目,记录复习(持续更新)

Java基础

1.String的最大长度

https://www.cnblogs.com/wupeixuan/p/12187756.html

2.集合

Collection接口的实现:
List接口:ArraryList、LinkedList、Vector
Set接口:HashSet、TreeSet
Qeque接口:ArrayQeque
Map接口的实现:
AbstractMap接口:HashMap、TreeMap
Dictionary接口:HashTable
集合关系图
https://img-blog.csdn.net/20160124221843905

3.集合扩容

https://www.jianshu.com/p/5a1ab09ebff1

ArrayList :
默认初始容量为10
线程不安全,查询速度快
底层数据结构是数组结构
扩容增量:原容量的 1.5倍
如 ArrayList的容量为10,一次扩容后是容量为15
扩容:把原来的数组复制到另一个内存空间更大的数组中
添加元素:把新元素添加到扩容以后的数组中
Vector :
默认初始容量为10
指定扩容增量或2倍(取最大值)
HashMap :
capacity 即容量,默认16。
loadFactor 加载因子,默认是0.75
threshold 阈值。阈值=容量*加载因子。默认12。当元素数量超过阈值时便会触发扩容。

4.红黑树

性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3 每个叶节点是黑色的。
性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

红黑树相比于BST和AVL树有什么优点
红黑树是牺牲了严格的高度平衡的优越条件为代价,它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能。红黑树能够以O(log2 n)的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决。当然,还有一些更好的,但实现起来更复杂的数据结构能够做到一步旋转之内达到平衡,但红黑树能够给我们一个比较“便宜”的解决方案。

相比于BST,因为红黑树可以能确保树的最长路径不大于两倍的最短路径的长度,所以可以看出它的查找效果是有最低保证的。在最坏的情况下也可以保证O(logN)的,这是要好于二叉查找树的。因为二叉查找树最坏情况可以让查找达到O(N)。

红黑树的算法时间复杂度和AVL相同,但统计性能比AVL树更高,所以在插入和删除中所做的后期维护操作肯定会比红黑树要耗时好多,但是他们的查找效率都是O(logN),所以红黑树应用还是高于AVL树的. 实际上插入 AVL 树和红黑树的速度取决于你所插入的数据.如果你的数据分布较好,则比较宜于采用 AVL树(例如随机产生系列数),但是如果你想处理比较杂乱的情况,则红黑树是比较快的

5.线程和进程

1、什么是进程?
进程是程序的而一次动态执行过程。
2、什么是线程?
个进程内部的控制序列, 是进程的一个实体,是进程的一条执行路径。程也就是一个轻量级进程(仅仅是在linux系统中。在windows系统中,进程就是经常进程,线程就是线程),每个线程都有自己的线程控制块,即一个进程至少有一个轻量级进程。
在线程组里面,所有的线程都是对等的关系,没有父线程的概念。
3、线程资源?
进程可以拥有资源,并且是系统拥有资源的基本单位 。线程本身并不拥有系统资源,仅有一些能保证独立运行的资源,这块资源的各个线程私有的。
4、线程的优点

  • 创建一个线程的代价比创建一个进程小的多
  • 线程之间的切换相比较进程切换需要操作系统做的工作少
  • 线程占用的资源比进程少
  • 可以充分利用多处理器的并行数量

5、线程的缺点

  • 编程难度大(编写和调试一个多线程程序比单线程困难的多)
  • 线程之间缺乏保护(时间上的分配或是共享了不该共享的数据造成很大影响)
  • 性能损耗(当计算密集型的线程的数量比可用的处理器多,那么就有可能有很大的性能损失,这里的性能损失是指增加了额外的同步和调度开销,二可用资源不变)

5.串行、并行和并发

串行:喂?你在做什么呢?买菜啊?好的,到家了说一声。啊?到家了?那你到幼儿园接娃吧。
串行的特点:前一个任务没搞定,下一个任务就只能等着。
并行:来,这是你的盖浇饭,这是我的胡辣汤。咱俩一起吃。
并行的特点:两个任务在同一时刻互不干扰的同时执行。
并发:你去买个菜,顺路把邮件发了;路过幼儿园时带娃回家。
并发的特点:同时安排若干个任务,这些任务可以彼此穿插着进行;有些任务可能是并行的,比如买菜、发邮件和去幼儿园的某些路途是重叠的,这时你的确同时在做三件事;但进菜市场和发邮件和接娃三者是互斥的,每个时刻只能完成其中一件。换句话说,并发允许两个任务彼此干扰。

6.用户态和内核态

https://blog.csdn.net/justlpf/article/details/99447462

7.JVM

JVM主要结构

我们都知道 Java 源文件,通过编译器,能够生产相应的.Class 文件,也就是字节码文件, 而字节码文件又通过Java虚拟机中的解释器,编译成特定机器上的机器码 。
也就是如下:
① Java源文件—->编译器—->字节码文件
② 字节码文件—->JVM—->机器码

1、 类加载器子系统(Class Loader Subsystem)

类加载器

类加载器

启动类加载器(Bootstrap ClassLoader) :负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类。
扩展类加载器(Extension ClassLoader) :负责加载 JAVA_HOME\lib\ext 目录中的,或通过java.ext.dirs系统变量指定路径中的类 库。
应用程序类加载器(Application ClassLoader): 负责加载用户路径(classpath)上的类库。
双亲委派机制:当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父 类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中, 只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的 Class),子类加载器才会尝试自己去加载。
采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载 器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载 器最终得到的都是同样一个Object对象。

JVM类加载机制分为五个部分:加载、连接(包括:验证、准备、解析)、初始化、使用、卸载

JVM类加载

1.1、加载
这个阶段会在内存中生成代表这个类的java.lang.Class对象,作为方法区的这个类的各个数据数据入口
1.2、 验证
确保.Class文件的字节流中的信息符合JVM的要求
1.3、准备
在方法区中分配这个变量所使用的内存空间

// 实际上变量a在准备阶段后初始化为0,将a赋值80的put static指令时程序被编译后,存放在类构造器<client>方法中
public static int a = 80;
// 在编译阶段会为a生成ConstantValue属性,在准备阶段虚拟机会根据ConstantValue属性将a赋值为80
public static final int a = 80;

1.4、解析
解析阶段是指JVM将常量池中的符号引用替换为直接引用的过程
符号引用:符号引用与虚拟机实现的布局无关,引用的目标并不一定要已经加载到内存中。各种虚拟 机实现的内存布局可以各不相同,但是它们能接受的符号引用必须是一致的,因为符号引用的字面量形式明确定义在Java虚拟机规范的Class文件格式中

  1. CONSTANT_Class_info
  2. CONSTANT_Field_info
  3. CONSTANT_Method_info

直接引用:直接引用可以是指向目标的指针,相对偏移量或是一个能间接定位到目标的句柄。如果有 了直接引用,那引用的目标必定已经在内存中存在。
1.5、初始化
初始化是类加载最后一个阶段 ,前面的类加载阶段之后,除了在加载阶段可以自定义类加载 器以外,其它操作都由JVM主导。到了初始阶段,才开始真正执行类中定义的Java程序代码。
注意以下几种情况不会执行类初始化:

  1. 通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。
  2. 定义对象数组,不会触发该类的初始化。
  3. 常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触发定义常量所在的类。
  4. 通过类名获取Class对象,不会触发类的初始化。
  5. 通过Class.forName加载指定类时,如果指定参数initialize为false时,也不会触发类初 始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。
  6. 通过ClassLoader默认的loadClass方法,也不会触发初始化动作。

2、运行时数据区(Runtime Data Area)

运行时数据区

6.1、程序计数器(线程私有)
一块较小的内存空间,是当前线程执行字节码的行号指示器,每个线程都要有一个独立的程序计数器。它在虚拟机中没有规定任何OutOfMemoryError情况的区域。
6.2、虚拟机栈或JVM栈(线程私有)
是描述java方法执行的内存模型,每个方法执行的同时都会创建一个和栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、返回地址。每一个方法从调用直至执行完成 的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

栈帧( Frame)是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接 (Dynamic Linking)、 方法返回值和异常分派( Dispatch Exception)。栈帧随着方法调用而创建,随着方法结束而销毁——无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异常)都算作方法结束。

栈帧

6.3、本地方法区(线程私有)
本地方法区和JVM栈作用相似。区别是JVM栈是入栈java方法服务,而本地方法栈是入栈Native方法服务
6.4、堆(线程共享)
是被线程共享的一块内存区。创建的对象数组都保存在Java堆中,也是垃圾收集器进行 垃圾收集的最重要的内存区域。从GC角度考虑,还可以将堆细分为:新生代(Eden区、From Survivor区和To Survivor区)和老年代
6.5、方法区或永久代(线程共享)
永久代(Permanent Generation), 用于存储被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版 本、字段、方法、接口等描述等信息外,还有一项信息是常量池

8. 线程池

线程池优点

  • 减少资源创建(线程的反复使用)
  • 降低系统时间开销(线程的创建需要时间,延迟请求)
  • 提高系统稳定性(避免无限创建线程导致的OutOfMemoryError)

一般创建方式有两种

  • 通过Executors工厂方法创建
  • 通过new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)自定义创建

线程池的创建不推荐使用Executors,容易内存溢出
Executors创建线程池

  1. newFixedThreadPool
    创建一个指定数量的线程池。当提交任务就创建一个工作线程,如果工作线程数量达到初始线程最大数,将提交的任务存入池队列中


    newFixedThreadPool
  2. newCachedThreadPool
    创建一个可缓存的线程池,如果线程池长度超出处理需要,可灵活回收空闲线程池,若无可回收,则创建新线程.
    这种类型的线程池特点是:
    工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。
    如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。
    在使用CachedThreadPool时,一定要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。


    newCachedThreadPool
  3. newSingleThreadExecutor
    创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO,优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。


    newSingleThreadExecutor
  4. newScheduleThreadPool
    创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。


    newScheduleThreadPool

ThreadPoolExecutor自定义创建线程池
四种构造方法

ThreadPoolExecutor构造方法

corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;

maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;

keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:

TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒

workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:

ArrayBlockingQueue
LinkedBlockingQueue
SynchronousQueue
PriorityBlockingQueue

ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和SynchronousQueue。线程池的排队策略与BlockingQueue有关。

threadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程做些更有意义的事情,比如设置daemon和优先级等等
handler:表示当拒绝处理任务时的策略,有以下四种取值:

1、AbortPolicy:直接抛出异常。
2、CallerRunsPolicy:只用调用者所在的主线程来运行任务。
3、DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
4、DiscardPolicy:不处理,丢弃掉。
5、也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。

线程池的submit()和execute()

当一个线程池里面的线程异常后:
1、当执行方式是execute时,可以看到堆栈异常的输出
原因:ThreadPoolExecutor.runWorker()方法中,task.run(),即执行我们的方法,如果异常的话会throw x;所以可以看到异常。
2、当执行方式是submit时,堆栈异常没有输出。但是调用Future.get()方法时,可以捕获到异常
原因:ThreadPoolExecutor.runWorker()方法中,task.run(),其实还会继续执行FutureTask.run()方法,再在此方法中c.call()调用我们的方法,
如果报错是setException(),并没有抛出异常。当我们去get()时,会将异常抛出。
3、不会影响线程池里面其他线程的正常执行
4、线程池会把这个线程移除掉,并创建一个新的线程放到线程池中
当线程异常,会调用ThreadPoolExecutor.runWorker()方法最后面的finally中的processWorkerExit(),会将此线程remove,并重新addworker()一个线程。

线程池大小,线程数计算公式

线程数计算

9.IO流

IO流

字节流:InputStream、OutputStream
字符流:Reader、Writer(这四个都是抽象类)
IO类设计时使用了装饰者设计模式

  1. 什么是比特(Bit),什么是字节(Byte),什么是字符(Char),它们长度是多少,各有什么区别

  2. Bit最小的二进制单位 ,是计算机的操作部分 取值0或者1

  3. Byte是计算机操作数据的最小单位由8位bit组成 取值(-128-127)

  4. Char是用户的可读写的最小单位,在java里面由16位bit组成 取值(0-65535)

  5. 按功能不同分为节点流、处理流
    节点流:以从或向一个特定的地方(节点)读写数据。如FileInputStream 
    处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,

6.序列化
将保存在内存中的对象数据转化为二进制数据流进行传输,任何对象都可以序列化
实现方法:实现java.io.Serializable接口
作用:把一个Java对象写入到硬盘或者传输到网路上面的其它计算机,这时我们就需要自己去通过java把相应的对象写成转换成字节流。对于这种通用的操作,我们为什么不使用统一的格式呢?没错,这里就出现了java的序列化的概念。在Java的OutputStream类下面的子类ObjectOutput-Stream类就有对应的WriteObject(Object object) 其中要求对应的object实现了java的序列化的接口。
7.反序列化
将二进制数据换回原对象
构造:ObjectInputStream(InputStream in)
方法:Object readObject() 从 ObjectInputStream 读取对象
8.transient关键字
以上序列化和反序列化实现了的对象序列化,但是可以发现,操作时是将整个对象的所有属性序列化,那么transient关键字可以将某些内容不需要保存,就可以通过transient关键字来定义
private transient string title;
此时title属性无法被序列化,

10.锁

1、ReentrantLock

ReentrantLock

(1)ReentrantLock特性

  • 依赖于AQS
  • 支持响应中断、超时、尝试获取锁
  • 必须手动调用unlock()释放锁
  • 支持公平锁和非公平锁
  • 可关联多个条件队列
  • 可重入锁
    (2)ReentrantLock与AQS关联
    非公平锁加密流程
static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
  • 若通过CAS设置变量State(同步状态)成功,也就是获取锁成功,则将当前线程设置为独占线程。
  • 若通过CAS设置变量State(同步状态)失败,也就是获取锁失败,则进入Acquire方法进行后续处理。
    其中Acquire为AQS核心方法

2、AQS

AQS中的队列是CLH(Craig、Landin and Hagersten队列)变体的虚拟双向队列(FIFO),AQS是通过将每条请求共享资源的线程封装成一个节点来实现锁的分配。


CLH队列

AQS使用一个Volatile的int类型的成员变量来表示同步状态,通过内置的FIFO队列来完成资源获取的排队工作,通过CAS完成对State值的修改。
CLH队列中等待的节点为AQS中的一个数据结构(Node)

 static final class Node {
        static final Node SHARED = new Node();
        static final Node EXCLUSIVE = null;
        static final int CANCELLED =  1;
        static final int SIGNAL    = -1;
        static final int CONDITION = -2;
        static final int PROPAGATE = -3;
        //当前节点在队列中的状态
        volatile int waitStatus;
        //前驱指针
        volatile Node prev;
        //后继指针
        volatile Node next;
        //表示处于该节点的线程
        volatile Thread thread;
        //指向下一个处于CONDITION状态的节点(由于本篇文章不讲述Condition Queue队列,这个指针不多介绍)
        Node nextWaiter;
  ....
}

线程锁的两种模式:

  • SHARED 表示线程以共享的模式等待锁
  • EXCLUSIVE 表示线程正在以独占的方式等待锁

waitStatus有下面几个枚举值:

  • 0 当一个Node被初始化的时候的默认值
  • CANCELLED 为1,表示线程获取锁的请求已经取消了
  • CONDITION 为-2,表示节点在等待队列中,节点线程等待唤醒
  • PROPAGATE 为-3,当前线程处在SHARED情况下,该字段才会使用
  • SIGNAL 为-1,表示线程已经准备好了,就等资源释放了

3、synchronized与lock

synchronized与Lock
  • synchronized是关键字,是JVM层面的底层啥都帮我们做了,而Lock是一个接口,是JDK层面的有丰富的API。
  • synchronized会自动释放锁,而Lock必须手动释放锁。
  • synchronized是不可中断的,Lock可以中断也可以不中断。
  • 通过Lock可以知道线程有没有拿到锁,而synchronized不能。
  • synchronized能锁住方法和代码块,而Lock只能锁住代码块。 Lock可以使用读锁提高多线程读效率。
  • synchronized是非公平锁,ReentrantLock可以控制是否是公平锁

4、产生死锁的四个条件

  • 互斥:某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。
  • 占有且等待:一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。
  • 不可抢占:别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。
  • 循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源。

synchronized的底层实现

锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。
锁升级的概念
synchronized(object)
唯一线程使用时:markword 记录这个线程Id 【偏向锁】
出现线程争用时:升级为【自旋锁CAS】,理解为绕着wc转圈
当自旋超过10次:升级为【重量级锁】,向操作系统(os)申请锁

(加锁代码)执行时间短,线程数少 使用自旋锁
(加锁代码)执行时间长,线程数多 使用系统锁

线程同步
Synchronized(object)
不能使用String常量 Integer Long....

锁的是对象不是代码
this xx.class
锁定方法 非锁定方法 可以同时执行
锁升级 偏向锁 自旋锁 重量级锁

https://www.cnblogs.com/wangwudi/p/12302668.html

5、volatile关键字

作用:使用valatile修饰的成员变量,就是告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性。

11.NIO(Non-blocking/New I/O)与BIO(传统IO)

BIO(传统IO)
BIO是一个同步并阻塞的IO模式,传统的 java.io 包,它基于流模型实现,提供了我们最熟知的一些 IO 功能,比如File抽象、输入输出流等。交互方式是同步、阻塞的方式,也就是说,在读取输入流或者写入输出流时,在读、写动作完成之前,线程会一直阻塞在那里,它们之间的调用是可靠的线性顺序。
NIO(Non-blocking/New I/O)
NIO 是一种同步非阻塞的 I/O 模型,于 Java 1.4 中引入,对应 java.nio 包,提供了 Channel , Selector,Buffer 等抽象。NIO 中的 N 可以理解为 Non-blocking,不单纯是 New。它支持面向缓冲的,基于通道的 I/O 操作方法。 NIO 提供了与传统 BIO 模型中的 SocketServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发

IO模型 BIO NIO
通信 面向流 面向缓冲
处理 阻塞IO 非阻塞IO
触发 选择器

NIO 的 Server 通信的简单模型

BIO 的 Server 通信的简单模型

NIO的特点:

  • 一个线程可以处理多个通道,减少线程创建数量;
  • 读写非阻塞,节约资源:没有可读/可写数据时,不会发生阻塞导致线程资源的浪费

12. Netty

Netty执行流程

引用:https://juejin.cn/post/6921858121774137352#heading-17

13.面向对象

一、面向对象(OOP):把数据及对数据的操作方法放在一起,作为一个相互依存的整体。
二、面向对象对象的三大特征
(1)封装
两层含义:一层含义是把对象的属性和行为看成一个密不可分的整体,将这两者“封装”在一个不可分割的独立单元(即对象)中;另一层含义指“信息隐藏”,把不需要让外界知道的信息隐藏起来,有些对象的属性及行为允许外界用户知道或使用,但不允许更改,而另一些属性或行为,则不允许外界知晓,或只允许使用对象的功能,而尽可能隐藏对象的功能实现细节。

封装的优点

  • 良好的封装能够减少耦合,符合程序设计追求“高内聚,低耦合”。
  • 类内部的结构可以自由修改。
  • 可以对成员变量进行更精确的控制。
  • 隐藏信息实现细节。

(2)继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承的优点

  • 提高类代码的复用性
  • 提高了代码的维护性
  • 使得类和类产生了关系,是多态的前提(它也是继承的一个弊端,类的耦合性提高了)

(3)多态
多态是同一个行为具有多个不同表现形式或形态的能力。
Java语言中含有方法重载与对象多态两种形式的多态:

方法重载:在一个类中,允许多个方法使用同一个名字,但方法的参数不同,完成的功能也不同。

对象多态:子类对象可以与父类对象进行转换,而且根据其使用的子类不同完成的功能也不同(重写父类的方法)。

面试题:什么是多态?实现多态的方法有哪些?

多态是面向对象的最后一个主要特征,它本身主要分为两个方面:

方法的多态性:重载与覆写
重载:同一个方法名称,根据不同的参数类型及个数可以完成不同的功能。
覆写:同一个方法,根据操作的子类不同,所完成的功能也不同。

对象的多态:父子类对象的转换。
向上转型:子类对象变为父类对象,格式:父类 父类对象 = 子类实例,自动;(Parent parent = new Child())
向下转型:父类对象变为子类对象,格式:子类 子类对象 = (子类)父类实例,强制。(前提条件是Parent parent = new Child();,若是Parent parent = new Parent()会报错)

多态的优点

  • 消除类型之间的耦合关系
  • 可替换性
  • 可扩充性
  • 接口性
  • 灵活性
  • 简化性

14.Final关键字

Final用于修饰类、成员变量和成员方法。final修饰的类,不能被继承(String、StringBuilder、StringBuffer、Math,不可变类),其中所有的方法都不能被重写(这里需要注意的是不能被重写,但是可以被重载,这里很多人会弄混),所以不能同时用abstract和final修饰类(abstract修饰的类是抽象类,抽象类是用于被子类继承的,和final起相反的作用);Final修饰的方法不能被重写,但是子类可以用父类中final修饰的方法;Final修饰的成员变量是不可变的,如果成员变量是基本数据类型,初始化之后成员变量的值不能被改变,如果成员变量是引用类型,那么它只能指向初始化时指向的那个对象,不能再指向别的对象,但是对象当中的内容是允许改变的。

  • final方法比非final快一些
  • final关键字提高了性能。JVM和Java应用都会缓存final变量。
  • final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
  • 使用final关键字,JVM会对方法、变量及类进行优化。
    https://blog.csdn.net/qq_42651904/article/details/87708198

15.Java序列化

定义:Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能
持久化对象时会用到对象序列化之外,当使用RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化
http://www.blogjava.net/jiangshachina/archive/2012/02/13/369898.html

16.cookie和session

在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。
而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。
https://www.cnblogs.com/l199616j/p/11195667.html

Spring

1. Bean的生命周期

执行调用Aware接口对应的方法
1.Spring对Bean进行实例化(相当于程序中的new Xx())
2.Spring将值和Bean的引用注入进Bean对应的属性中
3.如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()方法(实现BeanNameAware清主要是为了通过Bean的引用来获得Bean的ID,一般业务中是很少有用到Bean的ID的)和BeanClassLoaderAware
4.如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory(BeanFactory bf)方法并把BeanFactory容器实例作为参数传入。(实现BeanFactoryAware 主要目的是为了获取Spring容器,如Bean通过Spring容器发布事件等)
5.如果Bean实现了ApplicationContextAware接口,Spring容器将调用setApplicationContext(ApplicationContext ctx)方法,把y应用上下文作为参数传入.
(作用与BeanFactory类似都是为了获取Spring容器,不同的是Spring容器在调用setApplicationContext方法时会把它自己作为setApplicationContext 的参数传入,而Spring容器在调用setBeanFactory前需要程序员自己指定(注入)setBeanFactory里的参数BeanFactory )
执行before方法
6.如果Bean实现了BeanPostProcess接口,Spring将调用它们的postProcessBeforeInitialization(预初始化)方法
(作用是在Bean实例创建成功后对进行增强处理,如对Bean进行修改,增加某个功能;例如CommonAnnoationBeanPostProcessor)
调用执行init-method
7.如果Bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet方法,作用与在配置文件中对Bean使用init-method声明初始化的作用一样,都是在Bean的全部属性设置成功后执行的初始化方法。
执行after方法
8.如果Bean实现了BeanPostProcess接口,Spring将调用它们的postProcessAfterInitialization(后初始化)方法
(作用与6的一样,只不过6是在Bean初始化前执行的,而这个是在Bean初始化后执行的,时机不同;例如AbstractAutoProxyCreator AOP )
9.经过以上的工作后,Bean将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁
10.如果Bean实现了DispostbleBean接口,Spring将调用它的destory方法,作用与在配置文件中对Bean使用destory-method属性的作用一样,都是在Bean实例销毁前执行的方法。

2.Spring事务

事务具备ACID四种特性,ACID是Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)和Durability(持久性)的英文缩写。

Spring的事务传播行为

  • propagation_required:如果当前没有事务,就新建一个事务;如果当前存在事务,则加入事务。
  • propagation_required_new:如果当前没有事务,就新建一个事务;如果当前存在事务,则把当前事务挂起,新建一个事务。
  • propagation_supports:支持当前事务,如果没有事务,以非事务的方式执行。
  • propagation_not_supported:当前存在事务,把事务挂起,以非事务方式执行。
  • propagation_mandatory:如果当前存在事务,加入当前事务。否则抛出异常。
  • propagation_never:当前存在事务抛出异常。
  • propagation_nested:当前存在事务,则在嵌套事务内执行。如果当前没有事务,和propagation_required操作相似

3.Spring中使用的设计模式

  • 工厂模式:BeanFactory就是简单工厂模式体现
  • 单例模式: 提供全局使用的BeanFactory
  • 代理模式:AOP的功能就是用代理模式
  • 装饰者模式:Bean创建时,使用的Bean包装类BeanWrapper进行依赖注入
  • 观察者模式:spring中Listener的实现(1、提前生成多个事件 2、初始化事件多播器 3、准备好监听器 4、向多播器中注册监听器 5、事件发布,通知多播器进行相关逻辑)
  • 策略模式:Bean采用何种方法进行实例化(反射、工厂方法和cglib代理)

SpringMVC

SpringMVC请求流程

  1. 用户请求发送给DispatcherServlet,DispatcherServlet调用HandlerMapping处理器映射器;
  2. HandlerMapping根据xml或者注解找到相应的处理器,生成处理器对象返回给DispatcherServlet;
  3. DispatcherServlet会调用相应的HandlerAdapter;
  4. HandlerAdapter经过设配器调用具体的处理器去处理请求,生成ModleAndView返回给DispatcherServlet;
  5. DispatcherServlet将ModelAndView传给ViewReslover解析生成View返回给DispatcherServlet;
  6. DispatcherServlet根据View进行渲染试图

SpringBoot

Redis

1. 五大数据类型

  • String
  • Hash(数组+链表)
  • List(双向链表)
  • Set(value为空的HashMap,计算hash快速排重)
  • Zset(HashMap+跳表,HashMap里放的时成员到score的映射,跳表存放的是所有成员,查询效率高)

2.RDB与AOF区别

(1):R文件格式紧凑,方便数据恢复,保存rdb文件时父进程会fork出子进程由其完成具体持久化工作,最大化redis性能,恢复大数据集速度更快,只有手动提交save命令或关闭命令时才触发备份操作;
(2):A记录对服务器的每次写操作(默认1s写入一次),保存数据更完整,在redis重启是会重放这些命令来恢复数据,操作效率高,故障丢失数据更少,但是文件体积更大;

3.redis单线程为什么执行速度这么快?

(1):纯内存操作,避免大量访问数据库,减少直接读取磁盘数据,redis将数据储存在内存里面,读写数据的时候都不会受到硬盘 I/O 速度的限制,所以速度快
(2):单线程操作,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
(3):采用了非阻塞I/O多路复用机制

4.缓存雪崩以及处理办法

同一时刻大量缓存失效;
处理方法:
(1):缓存数据增加过期标记
(2):设置不同的缓存失效时间
(3):双层缓存策略C1为短期,C2为长期
(4):定时更新策略

5.缓存击穿原因以及处理办法

频繁请求查询系统中不存在的数据导致;
处理方法:
(1):cache null策略,查询反馈结果为null仍然缓存这个null结果,设置不超过5分钟过期时间
(2):布隆过滤器,所有可能存在的数据映射到足够大的bitmap中
google布隆过滤器:基于内存,重启失效不支持大数据量,无法在分布式场景
redis布隆过滤器:可扩展性,不存在重启失效问题,需要网络io,性能低于google

Mysql

1、数据库三范式

一、确保每列的原子性
二、非主键列不存在对主键的部分依赖(要求每个表只描述一件事)
三、满足第二范式,并且表中的列不存在对非主键的传递依赖

2、储存引擎

Mysql在V5.1之前默认存储引擎是MyISAM;在此之后默认存储引擎是InnoDB
MyISAM:

  • MyISAM不支持数据库事务,不支持外键。采用非聚集索引(非聚集索引主索引的子节点保存的是内存地址)。
  • MyISAM用一个变量保存整个表的行数,执行select count(*) from table 时读出变量即可。
  • MyISAM最小的锁力度是表锁,更新语句会锁住整张表,导致其他查询和更新会被阻塞。

InnoDB:

  • InnoDB支持数据库事务,采用聚集索引(聚集索引文件存放在主索引的叶子节点上),因此必须要有主键。
  • InnoDB最小的锁粒度是行锁

非聚集索引和聚集索引区别
(1)聚集索引就是以主键创建的索引,非聚集索引是以除了主键外的索引创建的
(2)每张表只能创建一个聚集索引,可以创建多个非聚集索引
(3)表记录的排序与聚集索引排序一致
(4)聚集索引存储记录是物理上连续的,非聚集索引是逻辑上连续的
(5)聚集索引适合排序,非聚集索引不适合排序场合(聚集索引的子节点就是数据,和数据按相同位置放在一起,索引即使数据。非聚集索引子节点只是保留了数据指针,数据并未排序)
(6)更新聚集索引代价比非聚集索引高

3.数据库事务隔离级别

数据库事务隔离级别

mysql默认事务隔离级别是可重复读

1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

2、不可重复读:事务 A 多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。

3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

计算机网络

1.网络模型

国际标准化组织(ISO)制定了OSI模型,OSI模型把网络通信分成7层,上从到下分别是应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。之后又将七层通信模型简化合并为四层模型,分别是应用层、传输层、网络层、网络接口层(各层之间的模型、协议统称为TCP/IP协议簇)

网络模型

OSI中的层 功能 TCP/IP协议族
应用层 文件传输,电子邮件,文件服务,虚拟终端 TFTP,HTTP,SNMP,FTP,SMTP,DNS,RIP,Telnet
表示层 数据格式化,代码转换,数据加密
会话层 控制应用程序之间会话能力;如不同软件数据分发给不同软件 ASAP、TLS、SSH、ISO 8327 / CCITT X.225、RPC、NetBIOS、ASP、Winsock、BSD sockets
传输层 端到端传输数据的基本功能 TCP、UDP
网络层 定义IP编址,定义路由功能;如不同设备的数据转发 IP,ICMP,RIP,OSPF,BGP,IGMP
数据链路层 定义数据的基本格式,如何传输,如何标识 SLIP,CSLIP,PPP,ARP,RARP,MTU
物理层 以二进制数据形式在物理媒体上传输数据 ISO2110,IEEE802

2.TCP/IP与HTTP

TCP/IP协议不仅仅指的是TCP和IP两个协议,而是指FTP、SMTP、TCP、UDP、IP等协议构成的协议簇
HTTP是应用层协议,主要解决如何包装数据
“IP”代表网际协议,TCP 和 UDP 使用该协议从一个网络传送数据包到另一个网络。把IP想像成一种高速公路,它允许其它协议在上面行驶并找到到其它电脑的出口。TCP和UDP是高速公路上的“卡车”,它们携带的货物就是像HTTP,文件传输协议FTP这样的协议等。

3.TCP和UDP

  • 都属于传输层协议
  • TCP(Transmission Control Protocol,传输控制协议)是面向连接的协议。在收发数据前,必须和对方建立可靠的连接。一个TCP连接需要有三次握手、四次挥手。
  • UDP(User Data Protocol,用户数据报协议)是一个非连接协议,传输数据之前源端和终端不建立连接,当它想传输时就简单的抓取应用程序的数据,尽可能快的扔到网上。

TCP和UDP

TCP和UDP协议的一些应用
TCP和UDP协议的一些应用

4.TCP三次握手

三次握手就是指TCP建立连接需要发送3个包。目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口信息大小。


三次握手
  • 第一次握手(SYN=1,seq=x)
    建立连接,客服端发送请求报文,报文首部中的同步位SYN=1,同时选择一个初始化序列号seq=x。此时客户端进入SYN-SENT(同步已发送状态)。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号;
  • 第二次握手(SYN=1,ACK=1,seq=y,ACKnum=x+1)
    服务器收到客户端的SYN报文段,如果同意连接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号ACKnum=x+1,同时,自己还要发送SYN请求信息,SYN=1,为自己初始化一个序列号 seq=y,服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号
  • 第三次握手(ACK=1,ACKnum=y+1)
    客户端收到服务器的SYN+ACK报文段,再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,确认号 ACKnum = y+1,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED(已建立连接)状态,完成TCP三次握手。

为什么需要三次握手呢?两次不行吗?
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

具体例子:“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”

5.四次挥手

TCP 的连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),也叫做改进的三次握手。客户端或服务器均可主动发起挥手动作。

四次挥手

  • 第一次挥手(FIN=1,seq=x)
    主机1(可以使客户端,也可以是服务器端),设置seq=x,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
  • 第二次挥手(ACK=1,ACKnum=x+1)
    主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknnum=x+1,主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“同意”你的关闭请求;
  • 第三次挥手(FIN=1,seq=y)
    主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK 状态
  • 第四次挥手(ACK=1,ACKnum=y+1)
    主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了,进入 CLOSED 状态。

主机 1 等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。

为什么连接的时候是三次握手,关闭的时候却是四次握手?

因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

由于 TCP 协议是全双工的,也就是说客户端和服务端都可以发起断开连接。两边各发起一次断开连接的申请,加上各自的两次确认,看起来就像执行了四次挥手。

6.HTTP

URI 和 URL
每个Web 服务器资源都有一个名字,这样客户端就可以说明他们感兴趣的资源是什么了,服务器资源名被称为统一资源标识符(Uniform Resource Identifier,URI)。URI 就像因特网上的邮政地址一样,在世界范围内唯一标识并定位信息资源。

统一资源定位符(URL)是资源标识符最常见的形式。 URL 描述了一台特定服务器上某资源的特定位置。

现在几乎所有的 URI 都是 URL。

URI 的第二种形式就是统一资源名(URN)。URN 是作为特定内容的唯一名称使用的,与目前的资源所在地无关
方法
Http协议定义了很多与服务器交互的方法,最基本的有4种,分别是GET,POST,PUT,DELETE. 一个URL地址用于描述一个网络上的资源,而HTTP中的GET, POST, PUT, DELETE就对应着对这个资源的查,改,增,删4个操作。 我们最常见的就是GET和POST了。GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。
状态码
每条HTTP响应报文返回时都会携带一个状态码。状态码是一个三位数字的代码,告知客户端请求是否成功,或者是都需要采取其他动作。

  • 1xx:表明服务端接收了客户端请求,客户端继续发送请求;
  • 2xx:客户端发送的请求被服务端成功接收并成功进行了处理;
  • 3xx:服务端给客户端返回用于重定向的信息;
  • 4xx:客户端的请求有非法内容;
  • 5xx:服务端未能正常处理客户端的请求而出现意外错误。

200 OK:表示从客户端发送给服务器的请求被正常处理并返回;
204 No Content:表示客户端发送给客户端的请求得到了成功处理,但在返回的响应报文中不含实体的主体部分(没有资源可以返回)
206 Patial Content:表示客户端进行了范围请求,并且服务器成功执行了这部分的GET请求,响应报文中包含由Content-Range指定范围的实体内容。
301 Moved Permanently:永久性重定向,表示请求的资源被分配了新的URL,之后应使用更改的URL;
302 Found:临时性重定向,表示请求的资源被分配了新的URL,希望本次访问使用新的URL;
303 See Other:表示请求的资源被分配了新的URL,应使用GET方法定向获取请求的资源
304 Not Modified:表示客户端发送附带条件(是指采用GET方法的请求报文中包含if-Match、If-Modified-Since、If-None-Match、If-Range、If-Unmodified-Since中任一首部)的请求时,服务器端允许访问资源,但是请求为满足条件的情况下返回改状态码;
400 Bad Request:表示请求报文中存在语法错误;
401 Unauthorized:经许可,需要通过HTTP认证;
403 Forbidden:服务器拒绝该次访问(访问权限出现问题)
404 Not Found:表示服务器上无法找到请求的资源,除此之外,也可以在服务器拒绝请求但不想给拒绝原因时使用;
500 Inter Server Error:表示服务器在执行请求时发生了错误,也有可能是web应用存在的bug或某些临时的错误时;
503 Server Unavailable:表示服务器暂时处于超负载或正在进行停机维护,无法处理请求;

参考:https://www.cnblogs.com/lazyegg/p/12710890.html

数据结构

链表

1、判断一个链表是否有环?

初始化两个指针slow、fast?分别前进一步和两步。再此当两指针再次相遇就是有环,fast到达null就是无环。

2、判断环形链表长度

初始化两个指针slow、fast?分别前进一步和两步。再此当两指针再次相遇的点就是环长度即slow的步数

1、AVLtree

定义:平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
平衡因子
某结点的左子树与右子树的高度(深度)差即为该结点的平衡因子(BF,Balance Factor)。平衡二叉树上所有结点的平衡因子只可能是 -1,0 或 1。如果某一结点的平衡因子绝对值大于1则说明此树不是平衡二叉树。为了方便计算每一结点的平衡因子我们可以为每个节点赋予height这一属性,表示此节点的高度。
https://blog.csdn.net/qq_25343557/article/details/89110319

2、哈夫曼树

目的:该树结构是找出存放一串字符所需的最少的二进制编码。
https://blog.csdn.net/qq_29519041/article/details/81428934

3、B树(B-tree)

概念:B树和平衡二叉树稍有不同的是B树属于多叉树又名平衡多路查找树(查找路径不只两个),数据库索引技术里大量使用者B树和B+树的数据结构。

4、KMP

子串每次移动的位置=已经匹配上的字符-最后一个匹配上的字符的最大对称数;

5、折半查找平均查找长度

n为长度
得平均查找长度为:((n+1)/n ) *log2(n+1)-1 (其中对数中的2为底数:即log以2为底(n+1)的对数)

注 : 当n很大时 ,可近似为 log2(n+1)-1

6、系统采用页式存储管理方案,若页号块号对应关系存于内存中,且内存的访问时间为1μs,则当快表命中率为50%和85%时,有效的存取时间分别为( )

当向内存中命中快表后,不要再去访问内存;
50%1μs+(1-50%)(1μs+1μs)=1.5μs
80%1μs+(1-80%)(1μs+1μs)=1.15μs
注有效时间=命中+未命中的时间

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容