1 使用一条SQL语句完成如下的结果,从图1到图2:
结果如下:
SELECT user_name ,
MAX(CASE course WHEN '数学' THEN score ELSE 0 END ) 数学,
MAX(CASE course WHEN '语文' THEN score ELSE 0 END ) 语文,
MAX(CASE course WHEN '英语' THEN score ELSE 0 END ) 英语
FROM user_score
GROUP BY user_name;
2 请写出冒泡排序算法的核心代码(手写),有没有优化的策略
/*
* 传统冒泡排序
*/
int[] a={3,2,5,8,4,7,6,9};
for(int i=0; i<8; i++) {
for(int j=0; j<=6-i; j++) {
if(a[j]>a[j+1]) {
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
for(int aa: a) {
System.out.println(aa);
}
优化1:定义一个flag,用来记录内层有没有进行交换,如果没有进行交换,则说明数组此时基本有序(已经全部有序),不用再进行判断,能够节省时间。
/**
* 冒泡排序优化一:设立flag
*
*/
int[] a={3,2,5,8,4,7,6,9};
boolean flag = true;
for(int i=0; i<8 && flag; i++) {
flag = false;
for(int j=0; j<=6-i; j++) {
if(a[j]>a[j+1]) {
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
flag = true;
}
}
}
for(int aa: a) {
System.out.println(aa);
}
优化2、定义一个标志位pos,用来记录每一次内循环最后一次交换的位置,如果全部有序或者局部有序,i 值减小,为零的时候就停止。
/**
* 冒泡排序优化二:记录最后交换位置
*/
int[] a={3,2,5,8,4,7,6,9};
int i = a.length -1;
while(i != 0) {
int pos = 0;
for(int j=0; j<i; j++) {
if(a[j]>a[j+1]) {
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
pos = j;
}
}
i = pos;
}
for(int aa: a) {
System.out.println(aa);
}
优化3:鸡尾酒排序(双向冒泡排序)
和传统冒泡的比较:不同的地方在于双向冒泡排序从低到高然后从高到低,而冒泡排序每次都是从低到高去比较序列里的每个元素。可以得到比冒泡排序稍微好一点的效能,原因是冒泡排序只能从一个方向进行比对,每次循环只移动一个项目
/**
* 冒泡排序优化三:双向冒泡排序(鸡尾酒排序)
*/
int[] a={3,2,5,8,4,7,6,9};
int left = 0;
int right = a.length - 1;
int temp;
while(left < right) {
for(int i=left; i<right; i++) { //找到当前排序元素里最大的那个,放在右侧
if(a[i] > a[i+1]) {
temp = a[i];
a[i] = a[i+1];
a[i+1] = temp;
}
}
right--;
for(int j=right; j>left; j--) { //找到当前排序元素里最小的那个,放在左侧
if(a[j]<a[j-1]) {
temp = a[j];
a[j] = a[j-1];
a[j-1] = temp;
}
}
left++;
}
for(int aa: a) {
System.out.println(aa);
}
3 请简要描述JVM的内存结构,描述清楚彼此之间的关系
JVM内存结构
我们都知道,Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途。其中有些区域随着虚拟机进程的启动而存在,而有些区域则依赖用户线程的启动和结束而建立和销毁。在《Java虚拟机规范(Java SE 8)》中描述了JVM运行时内存区域结构如下:
各个区域的功能不是本文重点,就不在这里详细介绍了。这里简单提几个需要特别注意的点:
1、以上是Java虚拟机规范,不同的虚拟机实现会各有不同,但是一般会遵守规范。
2、规范中定义的方法区,只是一种概念上的区域,并说明了其应该具有什么功能。但是并没有规定这个区域到底应该处于何处。所以,对于不同的虚拟机实现来说,是由一定的自由度的。
3、不同版本的方法区所处位置不同,上图中划分的是逻辑区域,并不是绝对意义上的物理区域。因为某些版本的JDK中方法区其实是在堆中实现的。
4、运行时常量池用于存放编译期生成的各种字面量和符号应用。但是,Java语言并不要求常量只有在编译期才能产生。比如在运行期,String.intern也会把新的常量放入池中。
5、除了以上介绍的JVM运行时内存外,还有一块内存区域可供使用,那就是直接内存。Java虚拟机规范并没有定义这块内存区域,所以他并不由JVM管理,是利用本地方法库直接在堆外申请的内存区域。
6、堆和栈的数据划分也不是绝对的,如HotSpot的JIT会针对对象分配做相应的优化。
如上,做个总结,JVM内存结构,由Java虚拟机规范定义。描述的是Java程序执行过程中,由JVM管理的不同数据区域。各个区域有其特定的功能。
4 请简述JAVA异常的体系结构,并列举几个常见的异常类
Thorwable类(表示可抛出)是所有异常和错误的超类,两个直接子类为Error和Exception,分别表示错误和异常。其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常, 这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。
1、Error与Exception
Error是程序无法处理的错误,它是由JVM产生和抛出的,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。
2、运行时异常和非运行时异常
运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
5 简述Session与Cookie直接的区别和联系
Session和Cookie的联系
Session和Cookie都是会话(Session)跟踪技术。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。但是Session的实现依赖于Cookie的sessionId(session的唯一标识需要存放在客户端)。
Session和Cookie的区别
1、cookie数据存放在客户端的浏览器上,session数据存放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的cookie并行cookie欺骗考虑到安全应当使用session。
3、session会在一定时间内保持在服务器上。当访问增多,会比较占用服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
4、单个cookie保持的数据不能超过4K,很多浏览器都限制一个站点最多保持20个cookie。
6 简要描述Redis的主从复制流程,及主从复制带来的好处与可能出现的隐患
Redis的主从复制策略是通过其持久化的rdb文件来实现的,其过程是先dump出rdb文件,将rdb文件全量传输给slave,然后再将dump后的操作实时同步到slave中。让从服务器(slave server)成为主服务器(master server)的精确复制品
主从复制的好处
做数据的热备,作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避免数据丢失。
架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,降低磁盘I/O访问的评率,提高单个机器的I/O性能。
读写分离,使数据库能支持更大的并发。在报表中尤其重要。由于部分报表sql语句非常的慢,导致锁表,影响前台服务。如果前台使用master,报表使用slave,那么报表sql将不会造成前台锁,保证了前台速度。
隐患
Redis目前存在的一个问题是主从复制在遇到网络不稳定的情况下,Slave和Master断开(包括闪断)会导致Master需要将内存中的数据全部重新生成rdb文件(快照文件),然后传输给Slave。Slave接收完Master传递过来的rdb文件以后会将自身的内存清空,把rdb文件重新加载到内存中。这种方式效率比较低下,尤其是在数据量大的情况下,毕竟网络闪断未必丢数据或者说丢的数据只是少部分,但却要为此付出将整个内存数据都重新传输一次的代价。如果能够将闪断过程的更新数据传递给Slave,那么就不需要将Master内存中的所有数据都传递给Slave了。
7 JSP中的 <%@ include%>与<jsp:include>的区别是什么?
对于静态包含,<%@include%>,中包含的文件,只是简单的嵌入到主文件中,就是在jsp页面转化成Servlet时才嵌入到主文件中,因为运行的结果是只生成了一个Servlet。
而对于动态包含<jsp:incude>,如果被包含文件是动态的,那么就会生成两个Servlet,也就是被包含文件也要经过jsp引擎编译执行生成一个Servlet,两个Servlet通过request和reponse进行通信。如果被包含的文件是静态的,那么这种情况和<%@include>就很相似,只生成了一个Servlet,但是他们之间没有进行简单的嵌入,而依然是通过request和reponse进行的通信。