-
抽象类与接口的区别
抽象类的本质还是一个类,所以类的基本功能它都拥有,除了不能实例化但却可以有构造方法(普通类当构造函数是pritave的时候也是不能实例化的),抽象类可以有抽象方法,交给子类去实现;接口中默认所有都是public的,普通方法是不能有方法体的,可以有default的默认方法且default方法是可以被覆盖的,static的方法必须有方法体不能被覆盖,且实现了这个接口的类不能直接调用静态方法需要通过 接口.方法()的方式调用,接口可以有字段(是static、final的) -
策略模式与模板模式区别
从解决问题的角度分析,策略模式是为了应对多种情况而设计的,模版模式是为了解决共性问题设计的;且模版模式更加针对的是一个流程,比如对合同的加工处理。 -
装饰者模式与代理模式区别
装饰者本质是对一个方法对装饰、加强,而代理模式更多是针对类来说对,举个例子:钢铁侠就是一个装饰者模式,大家都知道脱了这个皮就是没那么强大了;代理模式就像演员的替身,外人是不知道他们有什么不同的。 -
tcp/udp 区别
tcp是一个面向连接/可靠的传输层协议,udp同样也是传输层协议,但udp是无连接不可靠的;Tcp通过校验和,序号标识,重传控制,滑动窗口、确认应答实现可靠传输;如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。(重传控制会由于网络原因降低传输速率);tcp是点对点的传输方式,而udp可以一对一,一对多,多对多传输,同时udp的由于少了许多保证可靠的机制传输速率自然要快许多,有很好的实时性。TCP对系统资源要求较多,UDP对系统资源要求较少。 -
tcp/ip 三次握手、四次握手
连接建立:- 客户端->服务端:SYN seq=x
- 服务端->客户端:SYN seq=y ACK=x+1
- 客户端->服务端:ACK=y+1
传输数据:
- 客户端->服务端:SYN seq=x+1 ACK=y+1
- 服务端->客户端:ACK=x+2
连接断开:
- 客户端->服务端:FIN seq=x+2 ACK=y+2
- 服务端->客户端:ACK=x+3
- 服务端->客户端:FIN seq=y+1
- 客户端->服务端:ACK=y+2
为什么要这么做呢?举个很形象的例子:
三次握手:
“喂,你听得到吗?”
“我听得到呀,你谁啊?”
“我老王啊,今天你出去不?balabala……”
两次握手:
“喂,你听得到吗?”
“我听得到呀,你谁啊”
“喂喂,你听得到吗?”
“草,我听得到呀!!!!你TM谁啊”
“你TM能不能听到我讲话啊!!喂!”
“……”
四次握手:
“喂,你听得到吗?”
“我听得到呀,你听得到我吗?”
“我能听到你,你能听到我吗?”
“……不想跟傻逼说话”
-
四层网络协议
应用层(Http,FTP,Telnet)、传输层(TCP、UDP)、网络层(IP、OSPF开放最短路径优先协议)、物理层
7层模型中(ssl、tls和rpc属于会话层) -
数据库范式
- 第一范式:表中字段的属性不可再分(字段要求力度最细)
- 第二范式:依赖第一范式,另外包含两部分内容,一是表必须有一个主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。
- 第三范式:依赖第二范式,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
-
冒泡/选择/插入/快排/归并
- 冒泡排序:数组中相邻两个数字进行对比(for in for)
- 选择排序:轮询找出数组中最小的放到前面(for in for)
- 插入排序:后一个数字与前一个数字比较谁小谁在前
- 快速排序:找一个基准值,小于基准值的在左侧,大于基准值的在右侧,然后左右两边循环上面的操作
- 归并排序:将数组/2分割到最小单位1个数组元素,然后判断大小分别放入新的数组中组成新的数组,然后循环合并。
- 堆排序:升序大顶堆,降序小顶堆,先造大顶堆,然后每个堆顶与堆尾交换,缩短堆的大小重新调整大顶堆,循环。
-
二叉树遍历
- 深度优先:先序遍历、中序遍历、后序遍历;利用栈数据结构,先左后右完成遍历;
- 广度优先:利用堆数据结构,自上而下完成遍历
public void funcA(Node node){
// 先序
//System.out.println(node.val);
if (node.left!=null){
funcA(node.left);
}
// 中序
//System.out.println(node.val);
if (node.right!=null){
funcA(node.right);
}
// 后序
//System.out.println(node.val);
}
-
红黑树/b-tree/b+tree
- 红黑树:非黑即红,根节点一定为黑,叶子节点为黑,红节点的子节点都是黑的,每条路径都包含相同黑节点
- B树:非叶子节点的子节点至少2个即m个,根节点的子节点[2,m]个,根节点以外非叶子节点的子节点是[m/2,m],每个节点的关键字r=[m/2-1,m-1],r>2;非叶子节点关键字数=非叶子节点的子节点数-1;所有字节点位于同一层
- B+树:在B树的基础上加以改进,非叶子节点的指针数与关键字数一致,所有叶子节点增加一个链指针,所有关键字都在叶子节点出现
-
内部类与静态内部类的区别(局部内部类/匿名内部类)
参考普通字段和静态字段的区别,普通的内部类需要在外部类实例化以后才可访问,而静态类不需要实例化就可以访问;普通内部类不能有静态字段,而静态类可以有非静态字段;内部类实例化后通过内部指针访问外部类的对象,而静态类不能访问外部类非静态的字段或方法;局部类是方法内创建的类,作用域仅限于这个方法内;匿名内部类必须继承一个父类或实现一个接口,且不能为抽象类,因为匿名内部类没有类名故不能定义构造函数. -
https 请求过程
image -
类加载
new 一个类,这个类首先要判断是否已经加载过,这个过程通过双亲委派模型判断,如果没有加载过,则要先进行类的加载,加载过程是读取class文件的字节码,然后对字节码进行验证,验证字节码的格式,以及这个类的权限,准备阶段初始化常量与静态变量,解析阶段将符号引用转为直接引用,然后初始化执行赋值,构造方法。 -
gc
- 如何判断对象是否可回收通过:访问计数器、可达性分析;
- 回收算法:标记-清楚,复制,标记-整理
- 回收方式:分代回收(Young(Eden,from,to),Old,MetaSpace)
- Serail/SerialOld 串行回收
- Parallel New + CMS 高响应
- Parallel Scanvage + Paral OLd 高吞吐
-
字节码
魔数、次要版本号、主要版本号、访问标识、常量、this_class、super_class、interface、方法、属性 -
HashMap/HashTable/TreeMap/ConcurrentHashMap
HashMap\ConcurrentHashMap是基于数组、链表、红黑树的数据结构,不同的是HashMap是非线程安全的,扩容2倍的原因是因为效率问题,我们希望put进来的数据能构均匀分布,最直接的想法就是%,但位运算要比%快的多,所以h&(length-1)是等价的,为什么链表长度达到8时才升级为红黑树?链表查询效率是4,而红黑树是3,当然6的时候也可以升级为树,不过链表转化为树的过程的开销甚至要比查询的开销大的多。
HashTable 是线程安全的但key与value都不能为null,数据结构是数组+链表;TreeMap更直接就是一个红黑树结构。
差异 | HashMap | HashTable | TreeMap | ConcurrentHashMap |
---|---|---|---|---|
数据结构 | 数组、链表、红黑树 | 数组、链表 | 红黑树 | 数组、链表、红黑树 |
扩容 | 2倍,高低位拆分链表 | 2倍,重新hash拆分链表 | 无 | 2倍,高低位拆分链表 |
put | 允许key、value为null | 不允许key、value为null | 除根节点外key不能为null | 不许key、null为null |
size | 直接读取size | 直接读取count | counterCells+baseCount(put完毕后addCount是并发操作) | 直接读取size |
-
ArrayList/LinkedList
Array是基于数组的,查询快,Linked是基于链表的,插入删除快 -
List/Set
image
list允许重复/set不与许重复
-
Spring Ioc/Aop 实现原理
ioc通俗说为控制反转,在Spring中我们通常用来来注入属性,ioc实现的大致原理:收集Bean的信息,注册Bean的信息,实例化Bean并放入Map容器中。aop是在生成bean的beanPostProcessirAfter中处理的,本质是用动态代理,包装了这个类,根据pointCut的描述添加执行链。 -
Spring 事务实现原理
Spring的事务是依赖数据库的,本质就是通过代理模式帮我们做了commit(),rollback();
Spring事务的传播方式:
- 支持当前事务,如果没有弄个新的,然后用这个新的。
- 支持当前事务,如果当前已有新的,挂起,再弄个新的
- 支持当前事务,如果当前没有,则不开启事务。
- 支持当前事务,如果当前没有,则报异常。
- 线程池参数含义/原理
核心线程/最大线程/持续时间/时间单位/阻塞队列/拒绝异常处理器
excute 实际上是把这个runable对象包装为worker对象,通过worker对象中的thread调用start()方法,执行这个runable,最终执行的是runWorker方法,里面有个getTask的方法,线程开启后就会不停的重里面拿阻塞队列的任务去执行,如果等待时间达到预期设定时间还没有任务可执行,则这个线程执行完毕。
网友评论