总结秋招的一些面经

java 锁的补充:html

ReadWriteLock (ReadLock / WriteLock)
-> ReentrantReadWriteLock (同一线程对锁的重复获取)前端

写锁的降级 / 读锁的升级java

公平锁 / 非公平锁(synchronized使用非公平) (公平锁维护队列,效率低)mysql

自旋锁 (在 while 循环中一直判断某个条件,直到经过条件时才进入下个临界)linux

===============================nginx

 

volatile 不加时怎么通知另外一个线程读取刷新的数据
两个线程 (这个问题应该是从 JMM 的方面去回答)git

问题的答案 :
JMM决定一个线程对共享变量的写入什么时候对另外一个线程可见github

JMM是什么的问题:
JMM 就是 线程保存的本地变量副本和主内存之间进程通讯的机制, 能够适当涉及到 happens-before/volatile/synchronized/重排序方面的知识
happen-before : 讲一下传递性, 锁的解锁 happens-before 的加锁web


问题解决 --> https://segmentfault.com/a/1190000009828216
JMM模型
==============================面试

jvm 的各个区域的做用 (http://www.jianshu.com/p/54eb60cfa7bd)

共享:
方法区 :被加载的类信息、常量、静态变量 (代码存放编译完成后的信息)
堆 :存放对象实例、数组


线程私有:
虚拟机栈 :基本数据类型的数据,以及对象的引用
本地方法栈 :(native方法)
线程计数器 :执行字节码指示器,指示下一个执行的指令


StackOverflow 和 OutofMemory 的区别
若是线程须要的空间大于容许值,则为StackOverflowError;若是stack空间能够动态增长,但最后内存仍是不够,则为OutOfMemoryError。

每个JVM线程维护本身的JVM stack. JVM stack里面存放 JVM栈帧. 栈帧中存放 数据和中间结果(本地变量数组, 操做符栈, 和对runtime 常量池的引用). 这些数据都比较小(对象都在堆中, 栈帧仅存放对象引用), 因此想单纯经过 在栈帧中存放大数据的方法 去引入StackOverflowError, 基本是不现实的.通常都是由于方法调用嵌套层数过大.

(不断建立对象(位于堆中) -> OutofMemory )

 

==============================


ConcurrentHashMap:
Segment数组 (可重入锁)
HashEntry数组 (存储键值对) -》 修改HashEntry里的元素,须要获取对应的Segment锁


join : 是当前线程等待join线程执行完成以后再继续执行


CountDownLatch 等待N个点完成(构造器中传入的参数N)
countdown 方法减小计数器的值
await 方法阻塞当前线程 (有超时等待的版本)

 

CyclicBarrier 阻塞线程到同步点,知道全部的线程都到达同步点时才继续 (线程调用await方法通知到达同步点)
Semaphore 控制同时访问特定资源的线程数 (acquire方法获取, release方法释放)


线程池: Executor框架

FixedThreadPool 固定线程数量 LinkedBlockingQueue(无界队列)

SigleThreadExecutor 当个worker的池 LinkedBlockingQueue(无界队列)

CachedThreadPool 根据须要建立新线程的线程池 没有容量的SynchronousQueue(每一个插入操做必须等待另外一个线程的移除操做)

 

ScheduledThreadPoolExecutor extends ThreadPoolExecutor 能够指定多个对应的后台线程数

 

==============================

FutureTask Future
表明异步计算的结果 get方法在FutureTask完成阻塞,完成以后获取结果或者返回异常
实现:
AQS 同步框架, 里面封装了 CAS 相似的方法, 维护了一个阻塞队列, 位于头部的队列在执行完成以后通知以后的线程执行

 

Future:
定义一个泛型类,做为get方法的返回值, get方法执行了实现了callable接口的线程,callable接口定义了一个泛型类,
做为实现方法call的返回值类型 Runnable类的run方法没有返回值
FutureTask
结合了Runnable和Future接口
get方法用于获取执行任务的结果
run方法用于执行任务

 

Semaphore:(信号)
经过内部计数器控制一组线程在同一时间对某一资源的访问
acquire方法使计数器值递减
release方法使计数器值递增


CountDownLatch:
经过内部计数器控制全部线程线程处于等待(经过CountDownLatch.await()),直到计数器值归零后,全部任务一块儿执行
后续任务
1,资源初始化前,使用该资源的线程等待
2,释放服务前,依赖该线程的任务完成
3,多人游戏前,全部参与者终端的链接


CyclicBarrier:
(一)经过内部计数器控制全部线程相互等待,直到公共路障点(Common Barrier Point)
(二)当await方法使计数器递增数量到设定数量后,被await阻塞的方法继续执行


BlockingQueue:(最阻塞队列) 定义一些增删该查的方法,实现对多线程状况下 的处理
(笔试有遇过实现本身的BlockingQueue, 使用ReentrentLock,lock.await() lock.signal() 实现
参考 http://www.jb51.net/article/117204.htm)
(在并发场景中)
抛出异常: 当前线程没法执行则抛异常
特殊值: 当前线程没法执行返回null或false
阻塞: 没法操做时阻塞线程,直到操做完毕
超时: 在设定的时间内阻塞线程, 超时后放弃操做

 

 


==============================

gc 算法

判断gc:
引用计数 : 引用一次计数器加一
GC Roots Tracing : 根节点往下所搜,没连接的节点就gc


gc算法:
标记-清理 : 标记被回收的,而后清理, 会产生不少内存碎片
标记-整理 : 相似标记-清理, 清理完成经过整理减小碎片
复制 : 开阔相同的内存空间, 把未回收的复制到新的内存中

新生代基本采用复制算法,老年代采用标记整理算法。cms采用标记清理


使用不一样的GC算法:
+UseSerialGC
+UseParallelGC
+UseParNewGC
+UseConcMarkSweepGC
+UseG1


CMS concurrent mark and sweep:
1,初始标记
2,并发标记
3,从新标记
4,并发清理


查看java的工具:
jps jstat visualvm 默认的垃圾收集算法是:CMS (Linux中经过 netstat | grep java 也行吧)


双亲委派模型: 类加载的请求都会首先被传递到父类类加载器中, 每一个加载器的加载的文件路径不一样, ----》 目的为了保证jvm的安全性

BootstrapClassLoader c实现的类加载器

ExtensionClassLoader java路径下的ext/lib下的文件

SystemClassLoader 指定的classpath的文件
(各自加载的文件路径不一样)

 


自定义: loadclass findclass 类放在特殊的目录下,父类加载不到时,就使用本身的加载器加载

 

jvm中的

Eden区 新生代 新建立的对象存放的位置 触发minor gc

老年代 经历过屡次gc以后, 新生代中的对象被放入老年代中 触发 full gc / major gc

 

========================================================================

面试中的那点事:

前端 : jsp(jstl标签, 内置对象) js(选择器)

javase : hashmap hashtable等

javaee : 框架 spring springmvc hibernate和mybatis

数据库 : select语句 mysql的存储引擎(innodb和myisam)

linux : 基本的命令 vim

并发 : 锁(重入锁和synchronized) 原子类(CAS) FutureTask(AQS(CAS和一个队列)) ConcurrentHashMap(原理)

jvm : 结构 (堆,栈, 寄存器, 方法区) 类加载器(双亲委派模型)

gc : 收集算法 判断回收的方式 回收的地方

 

 

---------------------------星期天---------------------------------


ReadWriteLock (ReadLock / WriteLock)
-> ReentrantReadWriteLock (同一线程对锁的重复获取)

写锁的降级 / 读锁的升级

公平锁 / 非公平锁(synchronized使用非公平) (公平锁维护队列,效率低)

自旋锁 (在 while 循环中一直判断某个条件,直到经过条件时才进入下个临界)

===============================

 

volatile 不加时怎么通知另外一个线程读取刷新的数据
两个线程 (这个问题应该是从 jmm 的方面去回答)

问题解决 --> https://segmentfault.com/a/1190000009828216
JMM模型
==============================

jvm 的各个区域的做用 (http://www.jianshu.com/p/54eb60cfa7bd)

共享:
方法区 :被加载的类信息、常量、静态变量
堆 :存放对象实例、数组


线程私有:
虚拟机栈 :基本数据类型的数据,以及对象的引用
本地方法栈 :(native方法)
线程计数器 :执行字节码指示器,指示下一个执行的指令


StackOverflow 和 OutofMemory 的区别
若是线程须要的空间大于容许值,则为StackOverflowError;若是stack空间能够动态增长,但最后内存仍是不够,则为OutOfMemoryError。

每个JVM线程维护本身的JVM stack. JVM stack里面存放 JVM栈帧. 栈帧中存放 数据和中间结果(本地变量数组, 操做符栈, 和对runtime 常量池的引用). 这些数据都比较小(对象都在堆中, 栈帧仅存放对象引用), 因此想单纯经过 在栈帧中存放大数据的方法 去引入StackOverflowError, 基本是不现实的.通常都是由于方法调用嵌套层数过大.

(不断建立对象(位于堆中) -> OutofMemory )


==============================

gc 算法

判断gc:
引用计数 : 引用一次计数器加一
GC Roots Tracing : 根节点往下所搜,没连接的节点就gc

gc算法:
标记-清理
标记-整理
复制

---------------------------星期一---------------------------------


https://juejin.im/entry/58b7a7e78d6d8100652747fd
------------------------------------------
innnodb 和 myisam:
1,InnoDB不支持FULLTEXT类型的索引
2,InnoDB 中不保存表的具体行数(扫描表),当count(*)语句包含 where条件时,两种表的操做是同样的
3,对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,可是在MyISAM表中,能够和其余字段一块儿创建联合索引
4,DELETE FROM table时,InnoDB不会从新创建表,而是一行一行的删除
5,LOAD TABLE FROM MASTER操做对InnoDB是不起做用的,解决方法是首先把InnoDB表改为MyISAM表,导入数据后再改为InnoDB表,可是对于使用的额外的InnoDB特性(例如外键)的表不适用
6,InnoDB表的行锁也不是绝对的,假如在执行一个SQL语句时MySQL不能肯定要扫描的范围,InnoDB表一样会锁全表
7,MyISAM的索引和数据是分开的,而且索引是有压缩的,内存使用率就对应提升了很多

=====》 Innodb 支持事务处理与外键和行级锁


---------------------------------------------

进程间的通讯方式:

1,管道: 半双工(数据只能单向流动),只能在具备亲缘关系的进程间使用,进程的亲缘关系一般是指父子进程关系
2,有名管道:半双工,无亲缘关系进程间的通讯。
3,信号量:防止某进程正在访问共享资源时,其余进程也访问该资源
4,消息队列:消息的链表,存放在内核中并由消息队列标识符标识
5,信号:通知接收进程某个事件已经发生。
6,共享内存:被其余进程所访问的内存
7,套接字:不一样机器间的进程通讯


---------------------------------------------

CopyOnWriteArrayList :
写时加锁,当添加一个元素的时候,将原来的容器进行copy,复制出一个新的容器,而后在新的容器里面写,写完以后再将原容器的引用指向新的容器,而读的时候是读旧容器的数据,因此能够进行并发的读,但这是一种弱一致性的策略。
使用场景:CopyOnWriteArrayList适合使用在读操做远远大于写操做的场景里,好比缓存。

----------------------------------------------

线程池:
1. 若是当前池大小 poolSize 小于 corePoolSize ,则建立新线程执行任务。
2. 若是当前池大小 poolSize 大于 corePoolSize ,且等待队列未满,则进入等待队列
3. 若是当前池大小 poolSize 大于 corePoolSize 且小于 maximumPoolSize ,且等待队列已满,则建立新线程执行任务。
4. 若是当前池大小 poolSize 大于 corePoolSize 且大于 maximumPoolSize ,且等待队列已满,则调用拒绝策略来处理该任务。
5. 线程池里的每一个线程执行完任务后不会马上退出,而是会去检查下等待队列里是否还有线程任务须要执行,若是在 keepAliveTime 里等不到新的任务了,那么线程就会退出

====》 poolSize -》 corePoolSize -》 队列 -》maximumPoolSize -》 拒绝策略


----------------------------------------------

happens-before:
1.程序顺序规则
2.监视器锁规则
3.volatile变量规则
4.传递性
5.线程启动规则


----------------------------------------------

JMM --》 直接回答 6 个模块就好


----------------------------------------------
类加载器工做机制:
1.装载:将Java二进制代码导入jvm中,生成Class文件。
2.链接:
a)校验:检查载入Class文件数据的正确性
b)准备:给类的静态变量分配存储空间
c)解析:将符号引用转成直接引用
3:初始化:对类的静态变量,静态方法和静态代码块执行初始化工做。


----------------------------------------------

索引: B- , B+

----------------------------------------------

tcp的三次握手和四次挥手: (老生常谈)

(1)三次握手
1,client发送标志位SYN和随机序列号seq给server,进入SYN_SENT
2,server接受SYN标志获取创建连接请求,发送SYN,ACK和ack为接受seq+1和随机序列号seq
server进入SYN_RCVD状态
3,client接受确认,检查ack是否为seq+1,进入ESTABLISHED状态
发送ACK=1和ack为接受server的seq+1,server确认ack是否为本身发送的序列号值+1,
server进入ESTABLISHED状态


为何三次握手:
为了防止已失效的链接请求报文段忽然又传送到了服务端,形成server等待client链接而浪费资源

 

(2)四次挥手
1, client发送FIN client进入FIN_WAIT_1状态
2, server接受FIN 发送ack为接受的FIN值+1,server进入CLOSE_WAIT状态 client进入FIN_WAIT_2状态
3, server发送FIN 关闭server到client的链接,server进入LAST_ACK状态
4, client接受FIN client进入TIME_WAIT 发送ACK=1和ack为接受server的FIN+1,server进入CLOSED状态

为何四次挥手:
client端发送关闭链接请求,不发送数据但仍是能接受数据,
此时server端等待数据所有发送完成以后再发送关闭请求关闭链接


----------------------------------------------

tcp和udp的区别:
1,面向链接和面向无链接

2,tcp提供可靠传输,无差错,不丢失,不重复,按顺序,udp尽最大努力

3,tcp面向流, udp是数据包

4,tcp有拥塞控制,网络拥塞时主机下降发送速率

5,tcp一对一, udp一对多,多对多,多对一,一对一

6,tcp全双工通讯信道

7,tcp首部开销20字节,udp8字节

 

 

----------------------------------------------

http://mp.weixin.qq.com/s?__biz=MzA3NTUzNjk1OA==&mid=2651560829&idx=1&sn=30f50202d3dc3540e4bdba19e531a47e&chksm=8490342cb3e7bd3a88e56b59f054f3b01e47c509494d811f62cfa832e69cd380663b078816c8&mpshare=1&scene=1&srcid=0917bQEVdZKntgVoqKZZgRzi#rd
输入url以后发生的事情:

1,输入地址
浏览器匹配输入的地址,或者有些直接从缓存获取网页


2,浏览器查找域名的ip地址
(1)从hosts文件里查找对应的域名对应ip的记录,如有,则使用
(2)想本地DNS服务器发送一个DNS请求
(3)本地DNS服务器查找缓存中的记录,如有则返回结果,
若没有,递归向根DNS服务器查询
(4)根DNS服务器给给本地DNS服务器相对应的域名服务器的地址,进行迭代查询
(5)本地DNS服务器向域名服务器发送请求,获取域名解析服务器的地址
(6)域名解析服务器返回域名和ip对应关系,本地DNS服务器返回用户的同时
将对应关系缓存在本地DNS服务器中,以备以后查询


DNS两种查询:
(1)递归解析
DNS服务器自身不能解析,向根域名查询,再由根域名服务器一级一级向下查询

(2)迭代解析
DNS服务器自身不能解析,其余DNS服务器告诉能解析该域名的DNS服务器的ip地址,
让DNS服务器自身再发请求去查询

3, 浏览器向web服务器发送HTTP请求
TCP三次握手 四次挥手 看上面

4, 服务器的永久重定向响应
为何重定向:
所搜引擎把同一个网站不一样的地址定向到相同的网站去

301 :旧地址已经不存在, 新旧地址都到重定向的页面去
302 :旧地址存在, 搜索引擎抓取新地址而保持旧的网址


5, 浏览器跟踪重定向地址
浏览器访问地址了

6, 服务器处理请求
创建与服务器的链接,等待服务器返回结果

7,服务器返回HTTP响应

8,浏览器显示HTML

9,浏览器发送请求获取嵌在HTML中的图片等资源

----------------------------------------------

(https://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html)


java nio

BIO :
每次来一个请求(顾客),就分配到线程池中由一个线程处理,若是超出了线程池的最大上限,就扔到队列等待 。

nio :
mainReactor线程负责监听server socket,accept新链接,并将创建的socket分派给subReactor;subReactor能够是一个线程,也能够是线程池(通常能够设置为CPU核数),负责多路分离已链接的socket,读写网络数据

 

-----------------------------------------------

编程的题目都汇总在这了:

KMP

public class KMP {
public static int kmp(String str, String dest,int[] next){//str文本串 dest 模式串
for(int i = 0, j = 0; i < str.length(); i++){
while(j > 0 && str.charAt(i) != dest.charAt(j)){
j = next[j - 1];
}
if(str.charAt(i) == dest.charAt(j)){
j++;
}
if(j == dest.length()){
return i-j+1;
}
}
return 0;
}
public static int[] kmpnext(String dest){
int[] next = new int[dest.length()];
next[0] = 0;
for(int i = 1,j = 0; i < dest.length(); i++){
while(j > 0 && dest.charAt(j) != dest.charAt(i)){
j = next[j - 1];
}
if(dest.charAt(i) == dest.charAt(j)){
j++;
}
next[i] = j;
}
return next;
}
public static void main(String[] args){
String a = "ababa";
String b = "ssdfgasdbababa";
int[] next = kmpnext(a);
int res = kmp(b, a,next);
System.out.println(res);
for(int i = 0; i < next.length; i++){
System.out.println(next[i]);
}
System.out.println(next.length);
}
}

树的遍历

(关于树, 这 http://blog.csdn.net/tuke_tuke/article/details/51438751
讲解了许多题目, 看一下

给先序后序而后构建二叉树


快排

单例五个方式

TOPK

45度打印二维数组

快排 :

堆排序

dijkstra : http://www.cnblogs.com/junyuhuang/p/4544747.html


BFS

DFS


二叉树的高度(也有递归和非递归之分)


重构二叉树


最长公共子序列

 

---------------------------星期二---------------------------------

ArrayList扩容,HashMap扩容怎么实现

HashMap: (java8已经变成红黑树了,有空看一下吧)
两个参数 :初始容量 和 加载因子 (默认为16,和0.7)
每次增长元素,判断当前容量是否到达 当前容量*装载因子的大小
超过期,发生rehash操做,容量变为原来的2倍,原来的元素再通过hash放入新的桶数组中
(rehash操做判断原来容量是否为Integer.MAX_VALUE,如果,则直接把threshold设置为Integer.MAX_VALUE)

--》能够用 Collections的synchronizedMap方法使HashMap具备线程安全的能力,或者使用ConcurrentHashMap
ArrayList:
默认大小为10
扩容为原来大小的1.5倍+1
原来的数据经过 Arrays.copyOf 方法复制


------------------------------

TreeMap:
实现SortedMap接口,可以把它保存的记录根据键排序,默认是按键值的升序排序,也能够指定排序的比较器,
key必须实现Comparable接口或者在构造TreeMap传入自定义的Comparator,不然会在运行时抛出java.lang.ClassCastException类型的异常

(实现原理)

------------------------------
java8 中的 HashMap: 数组+链表+红黑树 (链表大于8时转化成红黑树 。。。 (红黑树的增删改,心好累。。))
Node是HashMap的一个内部类,实现了Map.Entry接口,本质是就是一个映射(键值对)
采用链地址法, 就是数组加链表的结合,对键hash以后放在对应桶数组下标的链表中

获取桶数组索引位置:
经过h & (table.length -1)来获得该对象的保存位,而HashMap底层数组的长度老是2的n次方
h& (length-1)运算等价于对length取模,也就是h%length

jdk1.8中 hash算法: 经过hashCode()的高16位异或低16位实现的:(h = k.hashCode()) ^ (h >>> 16)

-------------------------------

线程有多少种状态 (5种状态)

1,
新建状态:新建立了一个线程对象。

2,
就绪状态:线程对象建立后,其余线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

3,
运行状态:就绪状态的线程获取了CPU,执行程序代码。

4,
阻塞状态:阻塞状态是线程由于某种缘由放弃CPU使用权,暂时中止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的状况分三种:

(1)等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。

(2)同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。

(3)其它阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程从新转入就绪状态。

5,
死亡状态:线程执行完了或者因异常退出了run()方法,该线程结束生命周期。


-------------------------------


一致性哈希 。。。什么鬼

-------------------------------


图的的环检测(深搜)

有向图(DFS)

/*
* 1,白点集合,里面放还没explore的点
* 2,灰点集合,里面放正在explore的点,当前的灰点们表示一条正在explore的路径,这个路径上的每一个点都是灰的
* 3,黑点集合,里面放已经explore的点且这些点不构成环
*
* 黑色节点表示该节点的全部的邻接节点都已经被访问过了
* 若将要访问的点是个灰点,则表示发现了环
*/

public boolean hasCycleDirectedGraph(int n, int[][] edges) {// 前指后
HashSet<Integer> black = new HashSet<Integer>();
HashSet<Integer> white = new HashSet<Integer>();
HashSet<Integer> gray = new HashSet<Integer>();
List<List<Integer>> adjList = new ArrayList<List<Integer>>();
// 这里是在为每一个节点添加一个表达临近节点的集合
for (int i = 0; i < n; ++i) {
white.add(new Integer(i));
adjList.add(new ArrayList<Integer>());
}
// 这里是在 设置临近节点的集合
for (int[] edge : edges) {
adjList.get(edge[0]).add(new Integer(edge[1]));
}
//
for (int i = 0; i < n; i++) {
if (white.contains(i)) {
if (hasCycle(i, white, gray, black, adjList))
return true;
}
}
return false;
}

private boolean hasCycle(Integer vertex, HashSet<Integer> white, HashSet<Integer> gray, HashSet<Integer> black,
List<List<Integer>> adjList) {
white.remove(vertex);
gray.add(vertex); // current vertex is being visited
for (Integer succ : adjList.get(vertex)) { // successors of current
// vertex
if (white.contains(succ)) {
if (hasCycle(succ, white, gray, black, adjList)) {
return true;
}
} else if (gray.contains(succ)) {
return true;
} else if (black.contains(succ)) {
continue;
}
}
gray.remove(vertex);
black.add(vertex);
return false;
}

 

无向图 (并集查找 DFS)


并集查找:

/*
* 开始这个图只有顶点,没有边,咱们来一条一条的添加边。
* 每遇到一条边,判断这边的两个端点是否在同一个集合里?
*
* 在的话,表示有环:由于两个点在一个集合里就表示这两个点已经有一条路径了,如今再加一条路径,必然构成环。
* 不在的话,表示不构成环,咱们应该合并这两个集合:由于加上这条边,两个集合就被连起来了,合并成了一个集合
*
*
*/
public static void main(String[] args) {
int[][] edges = { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 1, 3 }, { 1, 4 } };
int n = 5;
UnDirectCircle directCircle = new UnDirectCircle();
System.out.println(directCircle.validTree(n, edges));
}

public boolean validTree(int n, int[][] edges) {
UnionFind uf = new UnionFind(n);
for (int[] edge : edges) {
int p = edge[0];
int q = edge[1];
if (uf.find(p) == uf.find(q))
return false;
else
uf.union(p, q);
}
return uf.count() == 1;
}
}

class UnionFind {
private int[] father;
private int count;

public UnionFind(int n) {
father = new int[n];
count = n;
// 初始化全部节点的父节点为节点自己
for (int i = 0; i < n; i++) {
father[i] = i;
}
}

public int count() {
return this.count;
}

public int find(int p) {
int root = father[p];

// 找到节点的最高的父节点
while (root != father[root])
root = father[root];

// as long as we get here, root is the final dad
// p 当前节点 father[p] 当前节点的父节点 迭代更新当前路径上的全部的节点为最高父节点
while (p != root) {
int tmp = father[p];
father[p] = root;
p = tmp;
}
return root;
}

public void union(int p, int q) {
int fatherP = find(p);
int fatherQ = find(q);
if (fatherP != fatherQ) {
father[fatherP] = fatherQ;
count--;
}
}
}

 

DFS:

public boolean validTree(int n, int[][] edges) {
HashSet<Integer> visited = new HashSet<Integer>();
List<List<Integer>> adjList = new ArrayList<List<Integer>>();
for (int i = 0; i < n; ++i)
adjList.add(new ArrayList<Integer>());
for (int[] edge : edges) {
adjList.get(edge[0]).add(edge[1]);
adjList.get(edge[1]).add(edge[0]);
}
if (hasCycle(-1, 0, visited, adjList)) // has cycle?
return false;
if (visited.size() != n) // is all connected?
return false;
return true;
}

private boolean hasCycle(Integer pred, Integer vertex, HashSet<Integer> visited, List<List<Integer>> adjList) {
visited.add(vertex); // current vertex is being visited
for (Integer succ : adjList.get(vertex)) { // successors of current
// vertex
if (!succ.equals(pred)) { // exclude current vertex's predecessor
if (visited.contains(succ)) {
return true; // back edge/loop detected!
} else {
if (hasCycle(vertex, succ, visited, adjList)) {
return true;
}
}
}
}
return false;
}

 

-------------------------------


缺页操做系统如何处理

每当所要访问的页面不在内存时,会产生一次缺页中断,
此时操做系统会根据页表中的外存地址在外存中找到所缺的一页,
将其调入内存。


  1. 保护CPU现场
  2. 分析中断缘由
  3. 转入缺页中断处理程序进行处理
  4. 恢复CPU现场,继续执行

在FIFO算法中,先进入内存的页面被先换出
在LRU算法中,最近最少使用的页面被先换出
在OPT算法中,在最远的未来才被访问的页面被先换出


-------------------------------


简单讲讲操做系统内存管理机制,
段式与页式内存管理的优缺点(顺道讲了下段页式)

 

 

 

-------------------------------

RPC (grpc dubbo thrift)

RPC 工做流程:
(1) client以本地调用方式调用服务
(2) client sub序列化调用请求的方法,参数,并发送到服务端
(3) server stub反序列化请求的方法和参数,并调用本地的服务
(4) server stub序列化返回值,并发送回client stub
(5) client stub反序列化收到的返回结果,并返回给调用的服务


原理 -》 JDK的动态代理 字节码 CGLIB


requestId ---》 解决多个请求状况下 response 对应 request
(1) 线程调用rpc时生成惟一requestId,而且和处理结果的回调对象callback
一块儿放入到ConcurrentHashMap中

(2) callback的get方法未获取结果则调用wait方法让当前线程等待

(3) server端返回结果时,根据requestId在ConcurrentHashMap中获取处理结果的Callback对象
调用callback的notifyAll唤醒线程


ps : RMI 只支持java应用(返回java对象和基本类型) rpc支持多语言

 


-------------------------------

(https的问题 : http://www.jianshu.com/p/072a657337ae)

HTTPS如何实现

1, 浏览器将本身支持的一套加密规则发送给网站
2, 网站从中选出一组加密算法与HASH算法,并发送证书信息(包含公钥)
3, 浏览器验证证书的合法性,若信任,生成随机密码,并用公钥加密随机密码,
用约定的HASH算法计算握手消息,并用随机密码对其加密,返回给网站
4, 网站用私钥解密浏览器的随机密码,再用密码解密握手消息,(?这里不懂?)并验证HASH是否一致
网站使用密码加密一段握手消息,发给浏览器
5, 浏览器解密并计算握手消息的HASH,验证与服务端发送的HASH是否一致,握手结束
通讯数据将由以前浏览器生成的随机密码并利用对称加密算法进行加密

 

非对称加密算法用于在握手过程当中加密生成的密码,
对称加密算法用于对真正传输的数据进行加密,
而HASH算法用于验证数据的完整性


Point:(客户端产生的对称密钥(随机密码)用非对称加密算法传输, 以后传输的消息使用对称密钥进行加密)
1,服务器下发的内容不可能被伪造,由于别人都没有私钥,因此没法加密。
强行加密的后果是客户端用公钥没法解开。
2,任何人用公钥加密的内容都是绝对安全的,由于私钥只有服务器有,
也就是只有真正的服务器能够看到被加密的原文。

 

-------------------------------


对称加密与非对称加密

对称加密 : 对原始数据的可逆变换 好比对一列数每位数字加一


非对称加密 :有两个秘钥,一个是公钥,一个是私钥。公钥加密的内容只有私钥能够解密,私钥加密的内容只有公钥能够解密

 

--------------------------------

信息安全传输
1,客户端和服务器直接的通讯只有本身能看懂
2,客户端和服务器能够校验数据是否被修改过
3,第三方没法冒充服务器

 

--------------------------------


通讯网络协议栈

物理层: 实现比特流的透明传输 CSMA/CD

数据传输层: 流数据封装成帧 ARP/RAPR
MAC子层的主要任务是,完成网络介质的访问控制;
LLC子层的主要任务是创建和维护网络链接,执行差错校验、流量控制和链路控制。

网络层: 分组传输 路由选择 ICMP

传输层:通讯子网和资源子网的接口和桥梁 提供可靠的端到端的差错和流量控制,保证报文的正确传输 TCP/IP UDP

会话层:向两个实体的表示层提供创建和使用链接的方法 RPC

表示层:处理用户信息的表示问题,如编码、数据格式转换和加密解密

应用层: 应用程序 HTTP FTP SMTP TELNET

 

--------------------------------

TCP拥塞控制,流量控制,

 

http://blog.csdn.net/yechaodechuntian/article/details/25429143


--------------------------------

滑动窗口协议,糊涂窗口

 

--------------------------------
http://java.jr-jr.com/2015/12/10/io-nio/

 

select和epoll : http://www.cnblogs.com/Anker/p/3265058.html

 

问题 :
Epoll与Select区别以及epoll优势,
为何通常状况下epoll性能比select好,ET模式与LT模式

select工做过程: (fd : 文件描述符)
1,调用select函数,将fd_set从用户空间拷贝到内核空间
2,注册回调函数
3,遍历fd,调用对应的poll方法(对于socket,有tcp_poll,udp_poll或者datagram_poll)
4,回调函数把当前进程挂到设备的等待队列中,
当设备收到一条消息(网络设备)或填写完文件数据后(磁盘设备),
会唤醒设备等待队列上睡眠的进程,这时current便被唤醒了。
5,poll方法返回读写操做是否就绪的状态码,并赋给fd
6,若遍历全部fd而没有可读写的状态码,调用select的进程调用schedule_timeout休眠一段时间,
等待设备资源可读写后唤醒,从新遍历fd,如此循环
7,把全部fd_set从内核空间拷贝到用户空间

缺点:
(1)每次调用select,都须要把fd集合从用户态拷贝到内核态,这个开销在fd不少时会很大

(2)同时每次调用select都须要在内核遍历传递进来的全部fd,这个开销在fd不少时也很大

(3)select支持的文件描述符数量过小了,默认是1024


select/poll每次调用都会线性扫描所有的集合,致使效率呈现线性降低


epoll epoll_create,epoll_ctl和epoll_wait,
epoll_create是建立一个epoll句柄;
epoll_ctl是注册要监听的事件类型;
epoll_wait则是等待事件的产生

epoll_create 每次注册新的事件到epoll句柄中时 把全部的fd拷贝进内核,保证了每一个fd在整个过程当中只会拷贝一次
epoll_ctl时把当前进程挂一遍,并为每一个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表
epoll_wait的工做实际上就是在这个就绪链表中查看有没有就绪的fd

epoll没有这个限制,它所支持的FD上限是最大能够打开文件的数目


总结:
1,select,poll实现须要本身不断轮询全部fd集合,直到设备就绪,
epoll只须要在唤醒时判断一下就绪链表是否为空就好了,这节省了大量的CPU时间
2,select,poll每次调用都要把fd集合从用户态往内核态拷贝一次
epoll只要一次拷贝,并且把current往等待队列(epoll内部定义的,不是设备等待队列)上挂也只挂一次

 


epoll 的 LT 和 EL :

1,LT (level triggered)是缺省的工做方式,而且同时支持block和no-block socket.
内核告诉你一个文件描述符是否就绪了,而后你能够对这个就绪的fd进行IO操做
若是你不做任何操做,内核仍是会继续通知你的

2,EL (edge-triggered)是高速工做方式,只支持no-block socket
当描述符从未就绪变为就绪时,内核经过epoll进行一次通知,以后再也不通知

--------------------------------

TCP 和 UDP 的区别
??发送3个80字节包,TCP与UDP下对端分别接受几回(其实就是TCP与UDP区别之一,TCP基于流)

都属于 OSI 中的传输层的协议
TCP 面向链接, UDP 无链接
TCP首部开销20字节,UDP首部开销8字节
TCP逻辑通讯信道是全双工的可靠信道,UDP则是不可靠信道
UDP没有拥塞机制,所以网络出现拥堵不会使源主机的发送效率下降
TCP的链接只能是点到点的,UDP支持一对一,多对一,多对多的交互通讯

TCP 应用:Telnet(远程登陆)、FTP(文件传输协议)、SMTP(简单邮件传输协议)。
TCP用于传输数据量大,可靠性要求高的应用
UDP 应用:NFS(网络文件系统)、SNMP(简单网络管理系统)、DNS(主域名称系统)、

--------------------------------

IPC有哪些,共享内存原理

 

-------------------------------

什么是缓存,为何须要缓存,有哪些缓存使用场景

缓存是临时存放数据(使用频繁的数据)的地方,介于外部请求和真实数据之间。

1,硬件缓存 硬盘(CPU)与外界接口(一般是内存)之间的暂存器
2,客户端缓存
3,服务端缓存 数据库链接

 

--------------------------------

 

https://yikun.github.io/2015/04/03/%E5%A6%82%E4%BD%95%E8%AE%BE%E8%AE%A1%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AALRU-Cache%EF%BC%9F/


LRU cache思路

(1) 基于HashMap和双向链表的实现
获取时从HashMap中获取Node,并更新到当前链表的头部
插入时,从HashMap获取Node,更新节点到链表头部并修改节点的值为新值


(2) 使用 LinkedHashMap 在构造函数传入 缓存容量,装载因子, 访问规则为true
(access-order为true时会更新访问的值到队列头部), 重写 removeEldestEntry方法

ps:关于LinkedHashMap的构造函数的第三个参数:
tt>true</tt> for access-order, <tt>false</tt> for insertion-order

private int capacity;
private Map<Integer, Integer> cache;
public LRUCache(int capacity) {
this.capacity = capacity;
this.cache = new java.util.LinkedHashMap<Integer, Integer> (capacity, 0.75f, true) {
// 定义put后的移除规则,大于容量就删除eldest
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return size() > capacity;
}
};
}


--------------------------------


操做系统调度算法

1,先来先服务调度算法(FCFS)
维护任务队列,先进队列的做业或进程先分配资源并建立进程投入运行,
直到完成或阻塞

2,短做业(进程)优先调度算法(SJF)
从队列中获取一个估计执行时间最短的任务,分配资源并执行

3,优先权调度算法
从任务队列中获取优先级最高的任务并执行
(1)非抢占式
选取一个最高优先级的任务后,不能再为另外一个优先级的任务分配资源
(2)抢占式
选取一个当前最高优先级的任务后,如有另外一个更高优先级的任务进入队列,则从新进行分配

4,高响应比优先调度算法
短做业优先算法 结合 优先权算法
让队列中的长任务在等待过程当中不断提升自身的优先级,
保证了长任务因为短任务的执行而没有分配资源的状况

5,时间片轮转法
为任务队列中的做业或进程程分配一个时间段,该时间段内
执行该任务,超时发送中断请求暂停执行


6,多级反馈队列调度算法
设置多个队列,为每一个队列分配不一样的时间片和不一样的优先级,
而后循环执行队列的任务
(最好的算法:没必要事先知道各类进程所需的执行时间,并且还能够知足各类类型进程的须要)

 

--------------星期天------------------


Nginx 负载均衡算法:
轮询
找最少的链接数
响应最快链接最少的
IP_HASH算法


--------------------------------

回话一致性:

(1) cookie insertion
服务器返回响应后,nginx向客户端植入cookie,客户端带着cookie,Nginx根据cookie转发请求


(2) stiky session
服务器第一次响应后,产生route信息, nginx经过访问route_cookie, route_session 中第一个不为空的
做为route

(3) learn
从已有的session中选择服务器

 

--------------------------------

InputStream 和 Reader 的区别

(1) InputStream是表示字节输入流的全部类的超类 读出来的 byte 数组

(2) Reader是用于读取字符流的抽象类 读出来的 char 或 String


区别
1,InputStreamReader , FileReader 涉及到编码问题, FileInputStream 不会1,
2,BufferReader类用来包装全部其 read() 操做可能开销很高的 Reader(如 FileReader 和InputStreamReader)
例如:
1) File file = new File ("hello.txt");
FileInputStream in=new FileInputStream (file);
InputStreamReader inReader=new InputStreamReader (in,"UTF-8");
BufferedReader bufReader=new BufferedReader(inReader);

2) File file = new File ("hello.txt");
FileReader fileReader=new FileReader(file);
BufferedReader bufReader=new BufferedReader(fileReader);

 

--------------------------------


IO和NIO的区别和原理

(1) IO是面向流的,NIO是面向缓冲区的
java io 从流中读取字节,直到读完全部的字节,中间并无缓存的过程;
java nio 先把数据读取到缓存中,在缓存中对数据进行移动操做,增长处理过程的灵活性


(2) 阻塞与非阻塞IO
当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据彻底写入。
Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,可是它仅能获得目前可用的数据,若是目前没有数据可用时,就什么都不会获取。直至数据变的能够读取以前,该线程能够继续作其余的事情
非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不须要等待它彻底写入,这个线程同时能够去作别的事情。 线程一般将非阻塞IO的空闲时间用于在其它通道上执行IO操做,因此一个单独的线程如今能够管理多个输入和输出通道

(3)
使用单线程Selector来管理多个通道,减小系统开销

 

--------------------------------

NIO中select的实现机制


(1) 建立Selector

(2) 向Selector注册通道

(3) SelectionKey

(4) 经过Selector选择通道

(5) wakeup

(6) close()

 

--------------------------------

synchronized 和 lock 的分区别:

(1) 二者都有相同的并发性和内存语义

synchronized 没有超时等待的机制
lock 有超时机制


(2) ReentrantLock 获取锁定三种方式
1, lock(), 若是获取了锁当即返回,若是别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
2, tryLock(), 若是获取了锁当即返回true,若是别的线程正持有锁,当即返回false;
3, tryLock(long timeout,TimeUnit unit), 若是获取了锁定当即返回true,若是别的线程正持有锁,会等待参数给定的时间,在等待的过程当中,若是获取了锁定,就返回true,若是等待超时,返回false;
4, lockInterruptibly:若是获取了锁定当即返回,若是没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断


(3) synchronized jvm层面上,能够监控,异常时自动释放锁
lock 必定要在 finally中调用unlock方法

 

 

--------------------------------

TCP/IP 协议栈

可分为三个层次:网络层、传输层和应用层。

在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。

在传输层中有TCP协议与UDP协议。

在应用层有:TCP包括FTP、HTTP、TELNET、SMTP等协议

 

---------------------------------

Http 长链接和短链接的区别


短链接: ( ----》服务器的链接 )

链接->传输数据->关闭链接
短链接是指SOCKET链接后发送后接收完数据后立刻断开链接

 

长链接: (操做频繁时, TCP的三次握手下降效率 --》 数据库的链接 )
链接->传输数据->保持链接 -> 传输数据-> 。。。 ->关闭链接。
长链接指创建SOCKET链接后无论是否使用都保持链接 (Connection:keep-alive)

 


--------------------------------

web app 是如何初始化spring和struts容器的

 

--------------------------------


servletlistener与fliter你知道多少

 

 

--------------------------------

生产者和消费者模式

 

--------------------------------

jsp 内置对象

request 客户端的请求

response 服务端返回结果

session 服务端建立的与用户请求相关的对象

application 对象中的内容直到应用关闭才会消失

page 当前jsp页面

pageContext 获取其余范围的参数信息(request, response等)

out 在浏览器中输出信息

exception 异常信息

config 获取服务器的配置信息, 在web.xml中提供jsp的相关参数

 


--------------------------------

星期天刷的yy的面经:


http://blog.csdn.net/brushli/article/details/50494037

 

--------------------------------

线程池的使用 :

先回答从 corePoolSize 等待队列 maximunPoolSize 拒绝策略


等待队列:
1, ArrayBlockingQueue 基于数组的有界阻塞队列 FIFO
2, LinkedBlockingQueue 基于链表的阻塞队列 FIFO
3, SynchronousQueue 不存储元素的队列, 插入操做都要等另外一个现成调用移除操做,不然插入一直处于阻塞状态
CachedThreadPool使用该队列
4, PriorityQueue 具备优先级的阻塞队列


拒绝策略 :
1, AbortPolicy 直接抛异常
2,CallerRunsPolicy 调用者本身运行该任务
3,DiscardOldestPolicy 丢弃最近的一个任务,并运行当前线程
4,DiscardPolicy 丢弃任务不处理


线程池执行任务:
execute 向线程池提交不须要返回值的任务
submit 提交有返回值的任务


线程池的关闭 :
shutdownNow
: 线程池置为STOP状态,中止全部正在执行的任务或暂停任务的列表,返回等待执行的任务列表
shutdown
: 线程池置为SHUTDOWN状态, 而后中断全部当前不在执行状态的线程

 

Executor框架 :
FixedThreadPool : 固定线程数的线程池

SingleThreadExecutor : 使用单个线程的executor
场景:保证顺序执行任务

CachedThreadPool : 根据须要建立新的线程

 


------------------------------------

工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式

适配器模式、装饰者模式、代理模式、外观模式、桥接模式、组合模式、享元模式

策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、
备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

并发型模式和线程池模式


struts中的 ExecutionChain 的责任链模式 OgnlValueStack中的装饰模式 (封装了一个ArrayList的对象)

hibernate的 SessionFacotory 的工厂模式

JDBC的 桥接模式

Spring bean 的单利模式

 

------------------------------------

如何才能产生死锁

产生死锁的四个必要条件:
一.互斥条件:所谓互斥就是进程在某一时间内独占资源。
二.请求与保持条件:一个进程因请求资源而阻塞时,对已得到的资源保持不放。
三.不剥夺条件:进程已得到资源,在末使用完以前,不能强行剥夺。
四.循环等待条件:若干进程之间造成一种头尾相接的循环等待资源关系。

 

------------------------------------

产生死锁的缘由:
一.由于系统资源不足。
二.进程运行推动的顺序不合适。
三.资源分配不当。

 

------------------------------------

 

死锁的预防

打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。
一.打破互斥条件。即容许进程同时访问某些资源。可是,有的资源是不容许被同时访问的,像打印机等等,这是由资源自己的属性所决定的。因此,这种办法并没有实用价值。
二.打破不可抢占条件。即容许进程强行从占有者那里夺取某些资源。就是说,当一个进程已占有了某些资源,它又申请新的资源,但不能当即被知足时,它必须释放所占有的所有资源,之后再从新申请。它所释放的资源能够分配给其它进程。这就至关于该进程占有的资源被隐蔽地强占了。这种预防死锁的方法实现起来困难,会下降系统性能。
三.打破占有且申请条件。能够实行资源预先分配策略。即进程在运行前一次性地向系统申请它所须要的所有资源。若是某个进程所需的所有资源得不到知足,则不分配任何资源,此进程暂不运行。只有当系统可以知足当前进程的所有资源需求时,才一次性地将所申请的资源所有分配给该进程。因为运行的进程已占有了它所需的所有资源,因此不会发生占有资源又申请资源的现象,所以不会发生死锁。
四.打破循环等待条件,实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会造成环路。全部进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。

 

------------------------------------

mysql数据库的各类骚操做:

备份mysql数据
mysqldump -u root -p goods t_admin > D:backup.sql
还原mysql数据
mysql -u root -p < D:backup.sql

查看mysql帮助
mysqldump --help

 


MySQL查询浏览器(MySQL Query Browser)

MySQL管理员(MySQL Administrator) 建立备份 、建立用户并分配权限、

MySQL迁移工具箱(MySQL Migration Tookit) 帮你把数据从别的数据库系统迁移到MySQL里。

MySQL工做台(MySQL Workbench) MySQL的建模工具。

 

查看mysql当前的状态:
(1)SHOW GLOBAL STATUS;
(2)SELECT * FROM information_schema.SESSION_STATUS;

 

(1)QPS (每秒查询量)、TPS(每秒事物量)
(2)增删改查的份量
(3)链接数、正在使用的链接数、最大链接数
(4)慢查询
(5)流量统计
(6)Innodb、MyISAM缓冲池


------------------------------------

聚簇索引和非聚簇索引

create cluster index 建立聚簇索引
create index 建立非聚簇索引


聚簇索引 : 表数据按照索引的顺序来存储,叶子节点储存了真实的数据行
非聚簇索引 :表数据存储顺序与索引顺序无关,叶结点包含索引字段值及指向数据页数据行的逻辑指针


汇集索引是一种稀疏索引,数据页上一级的索引页存储的是页指针,而不是行指针。
非汇集索引,则是密集索引,在数据页的上一级索引页,它为每个数据行存储一条索引记录。
(这里数据页的上一级的索引页, 能够参考两张图 -》 http://www.jb51.net/article/29693.htm)


聚簇索引:
在增长操做时,根据索引找到对应的数据页,为新数据腾出新空间,而后插入,可能会
形成索引页的拆分,并调整索引指针的操做
(非聚簇索引简单地放到表的末尾位置)

在删除操做时,会将下方数据上移填补空缺,如果最后一页,该数据页会被回收,
可能形成“索引合并”(数据页只有一行数据时,被移到临近的数据页)


聚簇索引使用于对范围值搜索的状况,由于索引值的行在物理相邻


------------------------------------

脏读: 读取到其余事物未提交的额数据
不可重复读: 同一个事物中两次读取到的数据不一样
幻读: 事物过程当中获取到其余事物新提交的数据


------------------------------------


java中的事物:

JDBC事物 : 数据库操做中一段连续的数据库操做 setAutoCommit(false)

JTA事物 : J2EE事物服务, 由UserTransaction、TransactionManager、Transaction组成

容器事物 :spring, hibernate框架中自带的事物实现

 

------------------------------------

select语句的优化:

1,对索引的考虑
(1),在where和join字段上增长索引
(2),索引创建在选择性好的字段上
(3),符合索引是否能够用and在where字句中替代
(4),频繁进行数据操做的表,不要创建太多的索引;
(5),删除无用的索引,避免对执行计划形成负面影响
2,只选择须要的字段
3,移除join和where语句中的计算字段

 

 

 

mysql和oracle的区别 http://blog.csdn.net/baidu_37107022/article/details/77043959

1,并发性:
oracle支持行级锁,并发性要好一些, mysql的innodb的行级锁须要依赖表的索引

2,事物:
oracle支持事物,mysql的innodb也支持

3,数据持久性:
oracle把提交的sql操做作日志备份,异常时可经过日志进行数据恢复

4,提交方式:
oracle须要用户手动提交
mysql默认自动提交

5,热备份:
oracle使用工具rman进行热备份, 备份时不影响用户使用数据库
mysql的myisam使用mysqlhostcopy,会给表加读锁,影响使用
innodb会备份表和索引可是不会备份.frm文件

6,其余写sql语句时的区别

(1)单引号的区别: mysql可使用双引号包含字符串,oracle只能用单引号
(2)自增加字段: mysql使用auto_increment, oracle使用自定义的自增加序列
(3)分页: mysql可使用limit, oracle使用rownum

 

------------------------------------

你对一些框架的理解:

(1)struts2:
Dispatcher (接受用户请求)
ActionProxy (代理用户请求和执行元素之间的关系)
ActionInvocation (核心调度器,调度Interceptor和Action返回Result)
ActionContext(提供了操做的数据环境)
Interceptor (拦截器)
Action (执行请求处理的地方) ValueStack(对ActionContext的数据进行操做)
Result (执行结果)

 

(2)hibernate:
Configuration
SessionFactory
Session
Trasaction
Query 或 Criteria


hibernate中的get和load
都会先从一级缓存中查找, 而后再去二级缓存中查找对应的数据
get若是没找到对应的数据,则返回null
load是对应配置文件中设置的lazy属性,若未找到对象,会抛出ObjectNotFoundException


(3)Spring
IOC : 使用反射

AOP : 使用动态代理 InvocationHandler 或者CGLib


(4)SpringMVC

用户的请求到DispatcherServlet, 分配到一个Controller, 返回一个ModelAndView,通过InternalResourceViewResolver, 返回到一个jsp页面

相关文章
相关标签/搜索