Java面试题集锦
- Java基础
1、ArrayList、Vector和LinkedList有什么区别?
答:ArrayList底层实现是数组,查找快,增删慢,线程不安全
Vector 和ArrayList内部实现一样,线程安全
LinkedList内部实现是链表,查找慢,增删快,封装了许多增删操作的方法
2、说说final、 finally和finalize的区别。
答: final可以修饰类、变量、方法
1)final修饰的类不能被继承
2)final修饰的方法不能被子类重写
3)final修饰的变量为常量,不能再次赋值
4)public static final 共同修饰的成员变量,我们成为全局常量,该变量应该所有字母大写
public static final string COUNTRY = "china";
finally需要结合try..catch语句一起使用
finalize()方法在对象被回收之前调用
3、jsp的生命周期
答:JSP生命周期就是从创建到销毁的整个过程,类似于servlet生命周期,区别在于JSP生命周期还包括将JSP文件编译成servlet。
以下是JSP生命周期中所走过的几个阶段:
JSP编译阶段:
servlet容器编译servlet源文件,生成servlet类
JSP初始化阶段:
加载与JSP对应的servlet类,创建其实例,并调用它的初始化方法
JSP执行阶段:
调用与JSP对应的servlet实例的服务方法
JSP销毁阶段:
调用与JSP对应的servlet实例的销毁方法,然后销毁servlet实例
很明显,JSP生命周期的四个主要阶段和servlet生命周期非常相似,下面给出图示:
4、简述servlet的生命周期
答:(1)加载和实例化
当客户端发送一个请求时,Servlet容器会查找内存中是否存在该Servlet实例,若存在,则直接读取该实例响应请求;若不存在,就创建一个Servlet实例。
(2) 初始化
实例化后,Servlet容器将调用init()方法进行初始化(一些准备工作或资源预加载工作)。
(3)请求处理
初始化后,Servlet处于能响应请求的就绪状态。当接收到客户端请求时,调用service()的方法处理客户端请求,HttpServlet的service()方法会根据不同的请求,转调不同的doXxx()方法。
(4)销毁
当Servlet容器关闭时,Servlet实例也随即销毁。其间,Servlet容器会调用destroy()方法去判断该Servlet是否应当被释放(或回收资源)。
原文: https://blog.csdn.net/hu1010037197/article/details/80215093
servlet生命周期图:
5、path和classpath环境变量的区别
答:path环境变量
当我们需要运行一个可执行命令的时候,系统首先会在当前目录找,然后去注册表找,如果都没有,最后会去path环境变量所配置的目录下去找。
查看和修改path环境变量的两种方式:
1)在dos命令行窗口,查看:set path 修改:set path=%path%;c:\java\bin
2)在我的电脑-->属性-->高级-->环境变量中查看和修改
classpath环境变量
JVM在运行一个程序时,首先会加载字节码,这时就需要找到所要运行的字节码文件
此时,虚拟机只会去classpath环境变量中配置的目录下去找
在命令行中,"."表示当前目录
path和classpath的区别:
操作系统执行一个.exe可执行文件的时候会去path下配置的目录下去找
java虚拟机在运行一个类的时候,会去classpath下配置的目录下去找
将 javac.exe 和 java.exe 可执行文件所在的目录追加到path环境变量中
将需要运行的 class 文件所在的目录追加到classpath环境变量中
6、String,StringBulider和StringBuffer有什么区别?
答:StringBuilder:存储快,线程不安全,适用于单线程;
StringBuffer:存储慢,线程安全,适用于多线程
执行效率:StringBulider > StringBuffer > String
7、各协议端口号
表1-3 常用TCP服务和端口 | 表1-4 常见UDP服务和端口 | ||||
TCP端口 | 服务名 | 功 能 | UDP端口 | 服务名 | 功 能 |
7 | echo | echo字符(用于测试) | 7 | echo | 在另一个数据包中返回用户的数据 |
9 | discard | 丢弃字符串(用于测试) | 9 | discard | 什么也不做 |
13 | daytime | 日期服务 | 13 | daytime | 返回日期 |
19 | chargen | 字符生成器 | 19 | chargen | 字符生成器 |
21 | ftp | 文件传输协议(FTP) | 37 | time | 返回时间 |
22 | ssh | 安全shell(虚拟终端或文件传输) | 53 | domain | 域名服务(DNS) |
23 | telnet | 远程登录 | 69 | tftp | 普通文件传输协议 |
25 | smtp | 电子邮件 | 111 | sunrpc | SUN的远程过程调用(RPC) |
37 | time | 时间服务 | 123 | ntp | 网络时间协议(Network Time Protocol,NTP) |
42 | nameserve | TCP名字服务 | 161 | snmp | 简单网络管理协议 |
43 | whois | NIC whois服务 | 512 | biff | 新邮件提示 |
53 | domain | 域名服务(DNS) | 513 | who | 收集关于用户登录到同一子网的其他机器的广播 |
79 | finger | 用户信息 | 514 | syslog | 系统日志工具 |
80 | http | WWW(万维网) | 517 | talk | 发送talk请求 |
110 | pop3 | 邮局协议3(POP3) | 518 | ntalk | 一个“新”的talk请求 |
111 | sunrpc | SUN的远程过程调用(RPC) | 520 | route | 路由信息协议 |
113 | auth | 远程用户名认证服务 | 533 | netwall | 写每个用户的终端 |
119 | nntp | 网络新闻传输协议(NNTP) | 2049 | NFS | 网络文件系统协议(NFS) |
143 | imap | 交互式邮件访问协议 | |||
443 | https | 用SSL加密的HTTP | |||
512 | exec | 在远程UNIX主机上执行命令 | |||
513 | login | 登录到远程UNIX主机(rlogin) | |||
514 | shell | 从远程UNIX主机获得shell(rsh) | |||
TCP端口 | 服务名 | 功 能 | |||
515 | printer | 远程打印 | |||
1080 | socks | SOCKS应用代理服务 | |||
2049 | NFS | TCP之上的NFS(NFS over TCP) | |||
6000~6001 | X | X Window系统 |
8 、面向对象得特征有哪些?
封装:
封装就是把描述一个对象的属性和行为的代码放到一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。对象是封装的最基本单位。
抽象:
抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,而忽略与目标无关的那些方面。比如:人是一个抽象的概念,人都有姓名和年龄这两个属性,我们将有姓名和年龄两个属性的事物称为人。
继承:
继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。
多态:
多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态
性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数
同名问题。
补充:多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
多态性是对象多种表现形式的体现。
9、接口和抽象类的区别?
接口特性
1)接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
2)接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
3)接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
抽象类和接口的区别
1)抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
3)接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。
(补充)接口和抽象类的区别:
抽象类:只声明方法而不去实现该方法的类就是抽象类
接口:是特殊的抽象类。在接口中,所有方法都是抽象的。
(1)接口是公开的,不能有私有的方法或变量,而抽象类是可以有私有方法或私有变量的;
(2)实现接口时一定要实现接口里定义的所有抽象方法,而实现抽象类可以有选择地重写需要用到的方法;
(3)接口可以实现多重继承,而一个类只能继承一个超类,但可继承多个接口
(4)在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,
而在interface中,所有的成员方法都是abstract的,并且不能实现它(没有方法体)。
(5)实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。
10、什么是面向对象?
答:类是对对象的抽象,对象是类的实例。我们生活的社会是由各种形态不同的事物所组成,而事物与事物之间都存在着各种各样的联系,正是这样的思想构成了面向对象编程思想的基础。在程序中用对象来描述现实的事物,每一个事物都在程序中都对应一个具体的对象,我们在程序中对对象进行操作来模拟现实中事物之间的关系,这就是所谓的万物皆对象。
11、服务器类型:
Server Type | Server Name |
应用服务器 | Jboss、JfOX3.0、openBJB、Resin、GlassFish、EasyBeans |
JSP 服务器 | Tomcat、Bejy Tiger、Geronimo、Jetty、Jonas、Jrun、Orion、Resin |
Java EE 服务器 | TongWeb、Apusic Application Server、IBM Websphere 、Sun Application Server、Oracle 的 Oracle9i/AS、Sun Java System Application Server、 Bea Weblogic、JBoss、开源GlassFish |
12、Session和Cookie的区别?
答:1)session保存在服务器,客户端不知道其中的信息;cookie保存在客户端,服务器能够知道其中的信息。
2)session中保存的是对象,cookie中保存的是字符串。
3)session不能区分路径,同一个用户在访问一个网站期间,所有的session在任何一个地方都可以访问到。而cookie中如果设置了路径参数,那么同一个网站中不同路径下的cookie互相是访问不到的。
4)session默认需要借助cookie才能正常工作。如果客户端完全禁止cookie,session这种方法将失效。
但是如果服务器端启用了url编码,也就是用URLEncoder.encode("index.jsp?id=3","UTF-8");把所有的url编码了,则会在url后面出现如下类似的东西:
index.jsp:jsessionid=fdsaffjdlksfd124324lkdjsf?id=3
服务器通过这个进行session的判断。
5)session在用户会话结束后就会关闭了,但cookie因为保存在客户端,可以长期保存。
6)COOKIE:是服务端向客户端写入的小的片段信息。session信息保存在服务器缓存区,不会在客户端显现。当你第一次登陆一个网站,服务器向你的机器写得片段信息。你可以在Internet选项中找到存放cookie的文件夹。如果不删除,cookie就一直在这个文件夹中。下次访问时会自动发送对应的Cookie到服务器端。
13、Overload与Override的区别?
答:重载 Overload 表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各
不相同(即参数个数或类型不同)。它是一个类中多态性的一种表现。
重写 Override 表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,我们说该方法被重写。它是父类与子类之间多态性的一种表现。
14、JSP和Servlet有什么区别?
答:servlet是运行在服务器上的java应用程序,而jsp其实就是servlet程序,它可以写java、html、JavaScript和css等等。在服务器端,jsp首先会被转化成servlet,然后再按照servlet的顺序执行。
jsp只是servlet的变种。
15、Jsp九大内置对象:
变量名 | 对象类型 |
page | this |
pageContext | PageContext |
request | HttpServletRequest |
response | HttpServletResponse |
session | HttpSession |
application | ServletContext |
config | ServletConfig |
out | JspWriter |
exception | Throwable |
16、JSP页面的静态包含和动态包含有什么区别?
答:参考https://www.cnblogs.com/wxgblogs/p/5602689.html
动态包含:<jsp:include page="被包含页面">
父页面和包含进来的页面单独编译,单独翻译成servlet后,在前台拼成一个HTML页面。
静态包含:<%@include file="被包含页面"%>
父页面和包含进来的页面,代码合并后,才一起翻译成servlet,反馈到前台,形成一个HTML页面。
17、list、set和map的区别?
答:list:是有序的允许有重复元素的collection
set:是无序的不允许有重复元素的collection
(list和set都是collection的子类)
map:将键映射到值的对象(是双列集合)
map和collection没有任何关系
18、什么是构造函数?
答:构造函数:
(1)构造函数的名称与类名相同,参数可以有一个或多个,不同的构造函数参数类型可以不同;
(2)构造函数没有返回值,不能用void来修饰;
(3)构造函数不能被直接调用,必须通过new运算符在创建对象时才会被调用。而一般函数是在程序执行到它的时候才会被调用。
特征:函数的名称与类名相同;
没有返回值类型声明;
不能在方法中使用return语句返回一个值。
注意:没有返回值类型声明不等同于”void”,void也是一种返回值类型声明,那就是没有返回值。
19、什么是多线程?
答:多线程:
线程:(thread)在一个程序中,能独立运行的程序片段就叫“线程”。它负责在单个程序里执行多任务。
进程:每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。
多线程:在单个程序中同时运行多个线程完成不同的工作,称为多线程.多线程主要是为了节约CPU时间。
使用多线程的好处:
(1)可把占据时间长的程序中的任务放到后台去处理
(2)可使程序的运行速度加快
(3)可释放资源和内存占用
20、什么是反射?
答:反射机制:
定义:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
功能:在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理。
21、什么是JDBC?它有什么作用?
答:JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
简单地说,JDBC 可做三件事:与数据库建立连接、发送 SQL 语句并处理结果
22、==和equals方法的区别?
==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符。
(1)equals方法是用于比较两个独立对象的内容是否相同
(2)字符串的比较基本上都是使用equals方法。
(3)如果一个类没有自己定义equals方法,它默认的equals方法(从Object 类继承的)就是使用==操作符
23、静态变量和实例变量的区别:
静态变量:
(1)静态变量前要加static关键字,可以通过类名.变量名的方式访问;
(2)静态变量属于类,只要类被加载,不用创建人和实例对象,就可以使用了;
实例变量:
(1)实例变量是某个对象的属性
(2)实例变量必须在创建对象后才会被分配空间,才能被使用
24、Integer与int的区别:
(1)int是java提供的8种原始数据类型之一。
(2)Java为每个原始类型提供了封装类,Integer是java为int提供的封装类。
(3)int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况
25、ceil:天花板,向上取整,Math.ceil(11.3)的结果为12,Math.ceil(-11.3)的结果是-11;
floor:地板,向下取整,Math.floor(11.6)的结果为11,Math.floor(-11.6)的结果是-12;
round:表示四舍五入,Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11。
26、求n!
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("求正整数的阶乘,请输入一个正整数:");
long num = scan.nextLong();
test(num);
}
static long test(long num){
long sum = 1; //阶乘的总和
if(num > 0 ){
for (int i = 1; i <= num; i++) {
sum *= i;
System.out.print(i+((i!=num)?"*":"="));//如果是最后一位的话,就不打印"*"号,打印"="号
}
System.out.print(sum);
return sum;
}else if(num == 0){
System.out.println(1);
return 1;
}else{
System.err.println("你的输入有误!");
return -1; //返回负数,说明有误
}
}
27、forward和redirect的区别?
forward:请求转发,是容器内的跳转,浏览器只向服务器发送一次请求,地址栏无变化,它比redirect更高效,并且有助于隐藏实际的连接;
redirect:请求重定向,是容器外的跳转,浏览器向服务器发送两次请求,地址栏有变化,在浏览器地址栏里可以看到跳转后的连接地址。
28、判断:
int a = 5;
Integer b = new Integer(5);
Integer c = new Integer(5);
判断a==b,b==c,a.equals(b),c.equals(b)
答:a==b? true
b==c? false
a.equals(b)? false
c.equals(b)? true
29、java中的常用类、包和接口:
类:1.java.lang.Object
2.java.lang.String
3.java.lang.System
4.java.io.file
5.java.io.FileInputStream
包:1.java.lang包
2.java.io包
3.java.swt包
4.java.util包
5.java.sql包
接口:1.java.util.List<E>
2.java.util.Map<E>
3.java.util.Iterator<E>
4.java.sql.CallableStatement
5.java.lang.Comparable<T>
30、VO和PO的区别?
答: vo和po:
vo(value object):值对象,对应页面中表单的属性
po(persistant object):持久化对象,映射数据库表
PO对象和VO对象相同点:都是javabean的对象,有set和get方法
PO对象和VO对象不同点:PO对象映射的是数据库的表,当数据库表的字段发生变化,PO对象同时要修改
VO对象对应页面中表单的属性,当表单属性发生变化的时候,VO对象可以对应页面的属性同时发生变化
总结:VO对象对应表现层
PO对象对应持久层
31、异常的捕获顺序:
答:按照从小到大的顺序捕获。
在写异常处理的时候,一定要把异常范围小的放在前面,范围大的放在后面,Exception这个异常的根类一定要放在最后一个catch里面,如果放在前面或者中间,任何异常都会和Exception匹配的,就会报已捕获到...异常的错误。
32、ajax之post提交:
(1)初始化XmlHttpRequest对象
function ajaxFunction(){
var xmlHttp;
try { // Firefox, Opera 8.0+, Safari
xmlHttp = new XMLHttpRequest();
}
catch (e) {
try {// Internet Explorer
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}
}
return xmlHttp;
}
(2)
window.onload=function(){
document.getElementById("ok").onclick=function(){
//1、创建ajax引擎
var xmlHttp=ajaxFunction();
//2、服务器返回相应结果
xmlHttp.onreadystatechange = function(){
if(xmlHttp.readyState == 4){
if(xmlHttp.status == 200 || xmlHttp.status == 304){
var data = xmlHttp.responseText;
alert(data);
}
}
}
//3、打开与服务器的连接
var url="../testServlet?c=10×tamp="
xmlHttp.open("post",url+new Date().getTime(),true);
xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
//4、发送请求数据
xmlHttp.send("a=8&b=9");
}
}
33、内存溢出与内存泄漏的区别?
答:参考https://www.cnblogs.com/Sharley/p/5285045.html
内存溢出(out of memory),是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。
内存泄露(memory leak),是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
34、如何对两个整数变量的值进行互换(不引入第三方变量)?
x=x+y;
y=x-y;
x=x-y;
35、两个集合如何取交集?
答:用双层for循环去比较,value值相同,counter加1。
36、List,ArrayList和LinkedList有什么区别?
答:List是一个有序、允许有重复元素的集合,它是ArrayList和LinkedList的父类;
ArrayList底层实现是数组,查找快,增删慢,线程不安全;
Vector 和ArrayList内部实现一样,线程安全;
LinkedList内部实现是链表,查找慢,增删快,封装了许多增删操作的方法。
37、Jquery去除div标签中的内容如何实现?
答:$(“#id”).empty() 或者 $(“#id”).html(“”);
38、HashMap和HashTable有何区别?
答:1)继承的类不同:HashMap继承自AbstractMap,HashTable继承Dictionary;
2)执行效率不同:HashMap线程不安全,是Hashtable的轻量级实现,效率高。HashTable线程安全,效率低;
3)put()对key和value的要求不同:
HashMap允许Entry的key或value为null;
HashTable不允许Entry的key或value为null
4)有无contains方法:HashMap无contains(),HashTable有contains().
39、如何防止form表单提交?
答:参考https://blog.csdn.net/Huozhiwu_11/article/details/78742886
1)用js禁掉提交按钮;
2)在数据库里创建唯一索引来有效防重;
3)在表单数据入库前,先校验数据库中是否存在与插入数据相同的记录,存在进行事务回滚,不存在执行事务提交;
40、String字符串底层 String s = new String(“abc”);创建了几个对象?
答:一共创建了3个对象,实际上"abc"本身就是文字池中的一个对象,在运行 new String()时,把文字池pool中的字符串"abc"复制到堆中,并把这个对象的应用交给s,所以创建了两个String对象,一个在pool中,一个在堆中。
41、java中有哪些临界值?
答:比如8中基本数据类型的取值范围:
数组长度array.lenght,超过数组定义的长度,报ArraylndexOutOfBoundException(数组角标越界异常)
42、同步和异步有什么区别?
答:同步交互(Sync):指发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待过程(同步可看作单线程);
异步交互(Async):指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待(异步可看作多线程)。
例如:吃饭和说话,只能一件事一件事的来,因为只有一张嘴。
和听音乐是异步的,因为,听音乐并不引响我们吃饭。
43、对外提供服务是那种方式?
答:webservice、http或RMI
44、jdk1.6,jdk1.7和jdk1.8有什么区别?
答:参考http://blog.csdn.net/sysmedia/article/details/53608681
45、请谈谈static
答:static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。
被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问。
static可以用来修饰类的成员方法、类的成员变量,另外可以编写static代码块来优化程序性能。
1)static方法
静态方法中不能访问类的非静态成员变量和非静态成员方法,但是在非静态成员方法中是可以访问静态成员方法/变量的。
即使没有显示地声明为static,类的构造器实际上也是静态方法。
2)static变量
static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它在类加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
static成员变量的初始化顺序按照定义的顺序进行初始化。
3)static代码块
static关键字还有一个比较关键的作用就是用来形成静态代码块以优化程序性能(只会在类加载的时候执行一次)。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
4)static是不允许用来修饰局部变量
46、什么是微服务?
答:微服务架构是将单个的整体应用分割成更小的项目关联的独立的服务。一个服务通常实现一组独立的特性或功能,包含自己的业务逻辑和适配器。各个微服务之间的关联通过暴露API来实现。
47、为什么要用微服务架构?
答:1)由于每个服务都是独立并且微小的,由单独的团队负责,可以采取敏捷开发模式,自由的选择合适的技术,甚至可以重写旧服务,当然都要遵守统一的API约定。
2)每一个微服务都是独立部署的,可以进行快速迭代部署,根据各自服务需求选择合适的虚拟机和使用最匹配的服务资源要求的硬件。
3)整体应用程序被分解成可管理的模块和服务,单个的服务可以更快的开发,更简单的理解和维护。
4)、一些需要进行负载均衡的服务可以部署在多个云虚拟机上,加入Nginx这样的负载均衡器在多个实例之间分发请求,这样不需要整个应用进行负载均衡了。
5)每个后端服务暴露一套REST API,大部分服务调用其他服务提供的API。每个服务都有自己的数据库模式,而不是共享单个数据库模式。尽管这会造成某些数据的冗余,但是对于微服务架构这个独立的数据库模式是必要的,确保了独立服务之间的松散耦合。
微服务的缺点:
1)微服务应用作为分布式系统带来了复杂性
2)多个独立数据库,事务的实现更具挑战性
3)测试微服务变得复杂,当一个服务依赖另外一个服务时,测试时需要另外一个服务的支持
4)部署基于微服务的应用也很复杂,整体应用程序部署只需要部署在一组相同的服务器上,在这些服务前面加入传统的负载均衡器即可。
1、JVM包含哪些部分?什么是GC算法?内存溢出是在什么情况下发生的?
答:jvm包含方法区、java堆、java栈和本地方法栈
Method area中存放了所有加载的类的信息,如:名称、修饰符,类中的静态变量,final类型的常量,field信息,类中的方法等;
Jvm stack存放的是变量;
Jvm heap存放对象实例
Native method stack存储每个本地方法调用的状态
GC:当内存中的某个对象不再被使用了,就会进行垃圾回收,GC会消耗一些资源和时间。
内存溢出:当方法区域需要使用的内存超过其允许的大小时,就会抛出OutOfMemory信息。
Jvm初始分配的内存由-Xms指定,默认是物理内存的1/64;最大分配内存由-Xmx指定,默认是物理内存的1/4.
2、JVM优化方法。
答:参考http://uule.iteye.com/blog/2114697
1、线程池和连接池有什么区别?
答:线程池:
把并发执行的任务传递给一个线程池,来替代为每个并发执行的任务都启动一个新的线程,只要池里有空闲的线程,任务就会分配给一个线程执行。在线程池的内部,任务被插入一个阻塞队列(blocking queue),线程池里的线程会去取这个队列里的任务。当一个新任务插入队列时,一个空闲线程就会成功的从队列中取出任务并执行它。
线程池经常应用在多线程服务器上。每个通过网络到达服务器的链接都会被包装成一个任务并且传递给线程池。线程池的线程会并发的处理连接上的请求。
连接池:是一个等待数据库连接的队列。
过程大概是这样:客户端向服务器端请求连接, 服务器端先看连接池中是否有空的连接,如果有空的连接就让该客户端连接,如果没有空的连接,那就看现有连接数是否达到连接池限定的个数,如果没有达到就为该客户端创建一个连接,如果达到了那就让该客户端排队,等其他客户端断开连接了,就让该客户端连接。
连接池会设定一个等待时间,超过这个时间就就是连接超时了, 一般服务器性能和网速都会有影响。SQLSERVER支持同时255个连接。
2、Java高并发访问怎么解决?
答:(1)尽量使用缓存,包括用户缓存、信息缓存等,可以大量减少与数据库的交互,提高性能。
(2)用jprofiler等工具找出性能瓶颈,减少额外的开销。
(3)优化数据库,包括sql语句(多做索引)和数据结构(分库、分表)的优化,提高查询效率。
(4)对统计的功能尽量做缓存,按天或定时统计相关报表,避免进行实时统计。
(5)将动态页面生成静态html来显示,减少容器的解析。
(6)使用集群解决单台服务器的瓶颈问题。
3、多台服务器分布式部署,如何保证数据的唯一性?
答:在数据库表中加version字段,引入乐观锁。
4、用Redis和Memcached缓存处理高并发时,如何将数据持久化?
答:Redis持久化有两种方式:
(1)AOF(append-only file),在执行写命令时,将被执行的命令复制到AOF文件末尾,以此来记录数据发生的变化。
(2)RDB持久化,在指定时间间隔内内存中的数据集快照写入磁盘(以快照方式写入二进制文件,默认文件名为dump.rdb)。
- 用IO流读取大文件(512M)用什么类?
答:ConcurrentHashMap
- Kafka推送数据一定安全吗?
答:不一定,当推送速度达到毫秒级时,会产生重复推送。
(1)kafka的数据交换是在哪里完成的?在内存中完成数据交换
(2)kafka缓存的数据在哪里?kafka使用broker来接受producer和consumer的请求,并把message持久化到本地磁盘。
(3)kafka数据怎么丢?
1)对于broker,落盘的数据,除非磁盘坏了,会丢;
2)对于内存中没有flush(清洗)的数据,broker重启会丢。
3)producer到broker;
4)broker到consumer;
(4)kafka数据重复处理:
1)kafka采用基于时间的SLA(服务水平保证),消息保存一定时间(通常为7天)后会被删除。重复数据一般出现在consumer端,这时可以采用log.cleanup.policy=delete定期删除机制。
2)将数据存储到redis中,在redis中去重;
3)调用kafka的api来编码去重;
7、如何理解分布式?什么是负载均衡?
答:分布式是以缩短单个任务的执行时间来提升效率的,而集群则是提高单位时间内执行的任务书来提升效率的。
分布式:指将不同业务部署在不同的服务器上;
集群:指将几台服务器集中在一起,实现同一业务。
负载均衡:负载均衡是由多台服务器以对称的方式组成一个服务器集合,每台服务器都
具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助。通过某种负载分担技术,将外部发送来的请求均匀分配到对称结构中的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。均衡负载能够平均分配客户请求到服务器列阵,籍此提供快速获取重要数据,解决大量并发访问服务问题。这种群集技术可以用最少的投资获得接近于大型
主机的性能。
8、synchronized的修饰对象有哪些?
答:synchronized是JAVA中的关键字,是一种同步锁。
它修饰的对象有:
1)修饰一个代码块,被修饰的代码块称为同步代码块,其作用范围是大括号{}括起来的代码,作用对象是调用这个代码块的对象
2)修饰一个方法,被修饰的方法称为同步方法,其作用范围是整个方法,作用的对象是调用这个方法的对象
3)修饰一个静态的方法,其作用范围是整个静态方法,作用对象是这个类的所有对象
静态方法是属于类的而不属于对象的。synchronized修饰的静态方法锁定的是这个类的所有对象(实例)。
4)修饰一个类,其作用范围是synchronized后面括号括起来的部分,作用对象是这个类的所有对象
9、两个线程访问两个synchronized方法会怎么样?
答:分四种情况:
1)两个并发线程调用同一实例的synchronized方法,第二个Thread会被第一个Thread阻塞,第一个Thread执行完后再执行第二Thread。两个Thread是互斥的。
2)两个并发线程调用不同实例的synchronized方法,会给两个实例创建两个锁,两个线程互不影响。
3)两个并发线程,一个访问对象的synchronized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。
4)两个并发线程,一个访问对象的synchronized非静态方法,一个访问对象的synchronized静态方法:因静态方法是属于类的,所以Thread2会被阻塞,2个Thread用的是同一把锁。
总结:无论synchronized关键字加在方法上还是对象(实例)上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。
10、谈谈缓存机制?
答:缓存就是将程序或系统经常要调用的对象存放在内存中,以便再次使用时可以快速调用,而不必去创建新的重复的实例。这样做可以减少系统开销,提高系统效率。
在项目中使用缓存,通常都是先检查缓存中是否存在目标数据,如果存在直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果。
缓存主要可分为二大类:
1)文件缓存,是指把数据存储在磁盘上,不管你是以XML格式,序列化文件DAT格式还是其它文件格式;
2)内存缓存,就是实现一个类中静态Map,对这个Map进行常规的增删改查。
11、缓存穿透是什么?如果一个线程在缓存中没有查到Key,去DB中去取了,这时又有很多线程来取此Key,也一起去DB去取,怎么办?
缓存雪崩
缓存雪崩是因为数据未加载到缓存中,或者缓存同一时间内大面积失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机。
解决思路:
1)采用加锁计数,或者使用合理的队列数量来避免缓存失效时对数据库造成太大的压力。这种办法虽然能缓解数据库的压力,但是同时又降低了系统的吞吐量。
2)分析用户行为,尽量让失效时间点均匀分布。避免缓存雪崩的出现。
3)如果是因为某台缓存服务器宕机,可以考虑做主备,比如:redis主备,但是双缓存涉及到更新事务的问题,update可能读到脏数据,需要好好解决。
缓存穿透
缓存穿透是指用户查询数据,在数据库没有查到,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库中查询。
解决思路:
1)如果查询数据库也为空,直接设置一个默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。
2)根据缓存数据Key的规则。例如我们公司是做机顶盒的,缓存数据以Mac为Key,Mac是有规则,如果不符合规则就过滤掉,这样可以过滤一部分查询。在做缓存规划的时候,Key有一定规则的话,可以采取这种办法。这种办法只能缓解一部分的压力,过滤和系统无关的查询,但是无法根治。
3)采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的BitSet中,不存在的数据将会被拦截掉,从而避免了对底层存储系统的查询压力。
大并发的缓存穿透会导致缓存雪崩。
缓存并发
如果网站并发访问高,一个缓存失效,可能会出现多个进程同时查询DB,同时设置缓存的情况,这也可能造成DB压力过大,还有缓存频繁更新的问题。
对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询。只不过利用锁的方式,会造成部分请求等待。
缓存失效
在高并发访问的时候,平常我们在设定一个缓存的过期时间时,可能会设置1分钟,5分钟...,但并发很高时可能会出在某一个时间同时生成了很多的缓存,并且过期时间都一样,这个时候就可能引发缓存同时失效,请求全部转发到DB,DB可能会压力过重。
那如何解决这些问题呢?
一个简单方案就是,将缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
- MQ消息队列
1、ActiveMQ、RobbitMQ等消息队列它们有哪些对象?实现原理是什么?
答:有生产者和消费者。Queue的原理是先进先出
2、谈谈你对消息的理解?
答:消息是JMS(JAVA消息服务)中的一种类型对象
1)消息包含:消息头、消息属性、消息自身
消息头主要定义消息的Topic、消息序列、消息类型
2)消息传送是建立在Observer设计模式基础上的
3)消息传送有两种模型
发布/订阅(Publish/Subscribe)模型:客户端发送消息到一个名为主题(topic)的虚拟通道中,每个订阅该主题的消费者都会接收到每条消息的一个副本。
点对点(Point to point)模式:客户端通过队列(queue)这个虚拟通道来同步和异步发送、接收消息,发送到队列的消息只能被一个接收者所接收,即使有多个消费者时也只能有一个消费者处理消息。
4)在消息接收上分为推模型和拉模型,它们使用轮询或事件驱动方式来进行消息接入。对消息服务而言,还要考虑消息消费模式:消息分派还是消息获取,消息的订阅与过滤机制、消息接入应用是同步处理还是异步处理。
5)什么时候用到消息机制?
A、异构系统集成,整合现有资源,提高资源的利用率
B、异步请求处理,减轻或消除系统瓶颈,提高用户生产率和系统的整体可伸缩性
C、组件解偶,增加系统的灵活性
Struts2
1、Struts在项目中的作用?
答:1)Struts 在项目主要起控制作用,只要用于web层(即视图层和控制层);
2)Struts把Servlet、JSP、自定义标签和信息资源(message resources)整合到一起实现了MVC结构,使项目结构更清晰,分工更明细。
3)Struts在项目中主要负责视图层、控制层,在视图层提供了大量的标签库,提高视图层的开发速度。在控制层使用中央控制器(Actionsupport)和配置文件(struts.xml),实现拦截用户请求、封装请求参数及页面导航。
答:参考https://blog.csdn.net/Huozhiwu_11/article/details/88889067
1)Intercepter是基于java反射机制的,是AOP的一种实现,而Filter是基于函数回调的。
2)Intercepter不依赖servlet容器,而Filter依赖于servlet容器。
3)Intercepter只对Action请求起作用,而Filter几乎对所有请求都起作用。
4)Intercepter可以访问Action上下文、值栈里的对象,而Filter不能。
5)在Action的生命周期中,Intercepter可以多次调用,而Filter只能在容器初始化时被调用一次。
拦截器(Intercepter) :是基于AOP的一种实现,就是在你的service或方法前调用一个方法,或在方法后调用一个方法,来达到拦截目的(比如:动态代理就是拦截器的简单实现)。在你调用方法前打印出字符串,也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。
下面通过demo来看一下过滤器和拦截器的区别:
使用拦截器进行/admin 目录下jsp页面的过滤
<package name="newsDemo" extends="struts-default" namespace="/admin">
<interceptors>
<interceptor name="auth" class="com.test.news.util.AccessInterceptor" />
<interceptor-stack name="authStack">
<interceptor-ref name="auth" />
</interceptor-stack>
</interceptors>
<action name="newsAdminView!*" class="newsAction" method="{1}">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="authStack"/>
</action>
下面是我实现的Interceptor class:
package com.test.news.util;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.test.news.action.AdminLoginAction;
public class AccessInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = -4291195782860785705L;
@Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
ActionContext actionContext = actionInvocation.getInvocationContext();
Map session = actionContext.getSession();
//except login action
Object action = actionInvocation.getAction();
if (action instanceof AdminLoginAction) {
return actionInvocation.invoke();
}
//check session
if(session.get("user")==null ){
return "logout";
}
return actionInvocation.invoke();
}
}
Intercepter主要特点在于:针对你不要的东西进行拦截,比如说,在一个BBS里面你希望人家不要留“TMD”的这个词,那你就可能采用Intercepter。
过滤器(filter):在用户发送request请求前,提前过滤掉一些信息,或者设置一些参数,然后再传入servlet或struts的action处理业务逻辑。比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或struts的action前统一设置字符集,或去除掉一些非法字符。
使用过滤器进行/admin 目录下jsp页面的过滤,首先在web.xml进行过滤器配置:
<filter>
<filter-name>access filter</filter-name>
<filter-class> com.test.news.util.AccessFilter </filter-class>
</filter>
<filter-mapping>
<filter-name>access filter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
下面是过滤的实现类:
package com.test.news.util;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class AccessFilter implements Filter {
public void destroy() { }
public void init(FilterConfig arg0) throws ServletException { }
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)arg0;
HttpServletResponse response = (HttpServletResponse)arg1;
HttpSession session = request.getSession();
if(session.getAttribute("user")== null && request.getRequestURI().indexOf("login.jsp")==-1 ){
response.sendRedirect("login.jsp");
return ;
}
filterChain.doFilter(arg0, arg1);
}
}
Filter主要特点在于:取你需要的东西,忽视那些不需要的东西。
3、Struts2中读取配置文件的顺序?
答: web.xml--->default.properties--->struts-default.xml--->truts-plugin.xml--->struts.xml
Spring
1、Spring在项目中的作用?
答:1)Spring是一个全方位的整合框架,在项目中对hibernate(持久层)和struts(表现层)进行整合,解决层与层之间的耦合问题;
2)Spring的作用贯穿了整个中间层,将Web层、Service层、DAO层及PO无缝整合;
3)Spring的IoC机制负责对象创建和依赖关系注入,上层框架不会渗透到下层组件,提高组件移植性和重用性,使得程序更灵活,上层框架不依赖实现而是依赖于抽象(委托接口)、使得实现类的变化不会影响上层组件,解决了层与层之间的藕合带来的维护或升级困难;
4)Spring 提供对AOP编程支持,实现对程序进行权限拦截和运行监控等功能,实现插件式编程。
5)Spring提供了对声明式事务的支持,只需要通过配置就可以完成对事务的管理。
Spring核心:
参考https://blog.csdn.net/Huozhiwu_11/article/details/88888391
控制反转(IoC / Inversion of Control):应用程序(调用者)本身不负责依赖对象(被调用者)的创建和维护,而是由外部容器负责创建组装。这样控制权就由应用程序转移到了外部容器,控制权的转移就是所谓的反转。
依赖注入(DI / Dependency Injection):在程序运行时,由外部容器将创建好的依赖对象注入到调用者组件中。
2、什么是AOP?有哪些应用场景?
答:参考http://www.cnblogs.com/xrq730/p/4919025.html
应用场景:权限认证、日志记录、事务处理和性能统计等
3、Spring是单例还是多例的?
答:默认是单实例的,scope=“singleton”。也可以设置成scope=“prototype”原型模式,针对每次不同的请求,bean容器均会生成一个全新的bean实例来供调用者使用。
4、Spring2.5和Spring3.0有什么区别?
答:参考http://blog.csdn.net/abigfrog/article/details/4748685
5、Spring如何管理事务?Spring实例在何时创建?
答:编程式事务管理:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚,在编程式事务中,必须在每个业务操作中包含额外的事务管理代码。
声明式事务管理:大多数情况下比编程式事务管理更好用。它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。事务管理作为一种横切关注点,可以通过AOP方法模块化。Spring通过Spring AOP框架支持声明式事务管理。
Spring管理事务:
参考https://blog.csdn.net/trigl/article/details/50968079
https://blog.csdn.net/chinacr07/article/details/78817449
创建bean时机(分两种情况):
第一:如果使用BeanFactory作为Spring Bean的工厂类,则所有的bean都是在被调用的时候实例化;
第二:如果你使用ApplicationContext作为Spring Bean的工厂类,则又分为以下几种情况: 1)如果bean的scope=“singleton”,并且lazy-init=“false”(lazy-init:延迟初始化,默认是false),则ApplicationContext启动的时候就实例化该Bean;
2)如果bean的scope=“singleton”,并且lazy-init=“true”,bean是在被调用的时候被实例化;
3)如果bean的scope=“prototype”,会每次调用时生产一个。
参考http://blog.csdn.net/jkl852qaz/article/details/52850298
https://blog.csdn.net/java_gchsh/article/details/78111200
SpringMVC
1、SpringMVC的原理是什么?
答:1)客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),web容器将请求转交给DispatcherServlet。
2)DipatcherServlet接收到这个请求之后将根据请求的信息(包括URL、Http方法、请求报文头和请求参数Cookie等)以及HandlerMapping的配置找到处理请求的处理器(Handler)。
3-4)DispatcherServlet根据HandlerMapping找到对应的Handler,将处理权交给Handler(Handler将具体的处理进行封装),再由具体的HandlerAdapter对Handler进行具体的调用。
5)Handler对数据处理完成以后将返回一个ModelAndView()对象给DispatcherServlet。
6)Handler返回的ModelAndView()只是一个逻辑视图并不是一个正式的视图,DispatcherSevlet通过ViewResolver将逻辑视图转化为真正的视图View。
7)Dispatcher通过model解析出ModelAndView()中的参数进行解析最终展现出完整的view并返回给客户端。
2、SpringMVC和Struts2的MVC有什么区别?
答:1)Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上SpringMVC就容易实现restful url,而struts2的架构实现起来要费劲,因为Struts2中Action的一个方法可以对应一个url,而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。
- 由上边原因,SpringMVC的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架,方法之间不共享变量,而Struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码 读程序时带来麻烦,每次来了请求就创建一个Action,一个Action对象对应一个request上下文。
3)由于Struts2需要针对每个request进行封装,把request,session等servlet生命周期的变量封装成一个一个Map,供给每个Action使用,并保证线程安全,所以在原则上,是比较耗费内存的。
- 拦截器实现机制上,Struts2有以自己的interceptor机制,SpringMVC用的是独立的AOP方式,这样导致Struts2的配置文件量还是比SpringMVC大。
- SpringMVC的入口是servlet,而Struts2是filter(这里要指出,filter和servlet是不同的。以前认为filter是servlet的一种特殊),这就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。
- SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去,使用起来也相对不方便。
- SpringMVC验证支持JSR303,处理起来相对更加灵活方便,而Struts2验证比较繁琐,感觉太烦乱。
- spring MVC和Spring是无缝的。从这个项目的管理和安全上也比Struts2高(当然Struts2也可以通过不同的目录结构和相关配置做到SpringMVC一样的效果,但是需要xml配置的地方不少)。
- 设计思想上,Struts2更加符合OOP的编程思想, SpringMVC就比较谨慎,在servlet上扩展。
- SpringMVC开发效率和性能高于Struts2。
11)SpringMVC可以认为已经100%零配置。
3、View和ModelAndView有什么区别?
答:View:视图;ModelAndView包含数据模型和视图;ViewResolver:视图解析器
4、SpringMVC中方法的返回值有哪些?
答:SpringMVC中返回值类型有:ModelAndView, Model, ModelMap, Map, View, String, void。
5、SpringMVC实现原理是什么?
答:1)启动服务器,根据web.xml的配置加载前端控制器(也称总控制器) DispatcherServlet 。在加载时会完成一系列的初始化动作。
2)根据servlet的映射请求(上面的HelloWorld实例中针对.do 请求),并参照“控制器配置文件”(即springMVC-servlet.xml 这样的配置文件),把具体的请求分发给特定的后端控制器进行处理(比如上例会分发给HelloWorld 控制器进行处理)
3)后端控制器调用相应的逻辑层代码,完成处理并返回视图对象( ModelAndView )给前端处理器。
4)前端控制器根据后端控制器返回的ModelAndView 对象,前端控器器根据视图对象返回具体页面给客户端。
6、AOP环绕通知
aop通知有:前置通知、后置通知、环绕通知和异常通知
环绕通知其实就是动态代理的另一种实现,它是对匹配方法的一种包裹,可以实现其他的通知。
该类型的通知使用的是@Around注解,并且使用ProceedingJoinPoint代替之前的JoinPoint来获取方法的参数和签名等信息,同时通过它的实例对象来调用匹配的方法,因此这个类型的参数是必须有的。另外,该通知还必须有返回值,它的方法可以对应JDK中的动态代理中的invoke()方法,它的返回值就是Target的返回值。
环绕通知和其他通知的区别:
1)目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知是不能决定的,他们只是在方法的调用前后执行通知而已,即目标方法肯定是要执行的。
2)环绕通知可以控制返回对象,即你可以返回一个与目标对象完全不同的返回值,虽然这很危险,但是你却可以办到。而后置方法是无法办到的,因为他是在目标方法返回值后调用。
Hibernate
1、Hibernate在项目中的作用?
答:1)Hibernate对JDBC进行了封装,实现了对象的持久化;
2)它实现了ORM(Object/Relation Mapping),提供了从 Java类到数据表的映射,也提供了数据查询和恢复等机制;
3)实现了连接池(一个等待数据库连接的队列);
4)操作数据库
2、Hibernate一级缓存和二级缓存有什么区别?
答:缓存:就是要将一些经常使用的数据缓存到内存或者各种储存介质中,当再次使用时可以不用去数据库中查询,减少与数据库的交互,提高性能。
一级缓存:是Session级别的,它在一个事务中才会启作用,session关闭时就失效了。一级缓存时hibernate自带的,不可以卸载;
二级缓存:是sessionFactory级别的,它的生命周期作用于应用程序的整个过程。适合放在二级缓存中的数据为:很少被修改的数据,不是很重要的数据,不会被并发访问的数据,以及参考数据。不适合放在二级缓存中的数据为:经常被修改的数据,财务数据,与其他应用共享的数据。二级缓存是一个可插拔的缓存插件。
3、hibernate中对象的三种状态:
自由态:通过new关键字创建的实体对象处于自由态
通过save()或saveOrUpdate()可转化为持久态
持久态:被保存到数据库中的实体对象
通过delete()可转化为自由态
通过clear()、close()或evict()可转化为游离态
游离态:脱离hibernate缓存管理的对象
通过update()或saveOrUpdate()可转化为持久态
通过delete()可直接转化为自由态
4、get和load加载的区别?
答:hibernate中,get()方法是直接加载,load()方法是延迟加载;
5、hibernate离线时如何去掉重复记录?
答:使用离线查询对象DetachedCriteria。该对象不是由session创建,而是由forClass或forEntityName来创建。
Mybatis
1、MyBatis配置文件中“#”和“$”有何区别?
答:(1)#会将传入的数据当做字符串,自动加上引号;$是将传入的数据直接显示。
(2)#能防止sql注入,而$不能
(3)$一般传入数据库对象。
2、MyBatis和Hibernate有什么区别?
答:1)hibernate是全自动,而mybatis是半自动。
hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。
2)hibernate数据库移植性远大于mybatis。
hibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库(oracle、 mysql等)的耦合性,而mybatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写sql的方法,如果sql不具通用性而用了很多某 数据库特性的sql语句的话,移植性也会随之降低很多,成本很高。
3)hibernate拥有完整的日志系统,mybatis则欠缺一些。
hibernate日志系统非常健全,涉及广泛,包括:sql记录、关系异常、优化警告、缓存提示、脏数据警告等;而mybatis则除了基本记录功能外,功能薄弱很多。
4)mybatis相比hibernate需要关心很多细节
hibernate配置要比mybatis复杂的多,学习成本也比mybatis高。但也正因为 mybatis使用简单,才导致它要比hibernate关心很多技术细节。mybatis由于不用考虑很多细节,开发模式上与传统jdbc区别很小,因 此很容易上手并开发项目,但忽略细节会导致项目前期bug较多,因而开发出相对稳定的软件很慢,而开发出软件却很快。hibernate则正好与之相反。 但是如果使用hibernate很熟练的话,实际上开发效率丝毫不差于甚至超越mybatis。
5)sql直接优化上,mybatis要比hibernate方便很多
由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。而 hibernate的sql很多都是自动生成的,无法直接维护sql;虽有hql,但功能还是不及sql强大,见到报表等变态需求时,hql也歇菜,也就 是说hql是有局限的;hibernate虽然也支持原生sql,但开发模式上却与orm不同,需要转换思维,因此使用上不是非常方便。总之写sql的灵 活度上hibernate不及mybatis。
1、JDBC连接mysql数据库源码
create database test character set utf-8;
use test;
create table users{
id int(4) primary_key auto_increment,
name varchar(20),
password varchar(20)
}character set utf-8;
insert into users(id,name,password) values(1,'zhangsan','zs');
insert into users(id,name,password) values(2,'lisi','ls');
insert into users(id,name,password) values (3,'wangwu','ww');
public class jdbcConnect(){
Class.forName(com.mysql.jdbc.Driver());
String url="jdbc:mysql://localhost:3306/test";
String user="root";
String password="root";
Connection con=DriverManager.getConnection(url,user,password);
Statement statement=con.createStatement();
String sql="select * form users";
ResultSet rs=statement.executeQuery(sql);
while(rs.next()){
Integer id=rs.getInt(id);
String name=rs.getString(name);
String password=rs.getString(password);
system.out.println("id|name|password",id+"|"+name+"|"+password);
}
rs.close();
statement.close();
con.close();
}
2、mysql中字段区分大小写吗?
答:默认情况下不区分。可以使用show Variables like '%table_names'查看lower_case_table_names的值,0代表区分,1代表不区分。
3、分表是水平分表还是垂直分的?它们有什么区别?
答:水评分表:一张表的数据划分到不同的数据库中,两个数据库的表结构一样(以时间节点划分)。
垂直分表:按照业务逻辑把存储内容比较多的字段分到新表中,可使表存储更多数据(以字段划分)。
4、索引和聚合索引有什么区别?
答:索引作用:1)创建唯一索引可以保证数据记录的唯一性;
2)加快数据检索速度;
3)加速表之间的链接;
4)在使用order by和group by子句中进行检索数据时,可以减少查询中排序和分组的时间;
5)使用索引可以在检索数据时使用优化隐藏器,提高系统性能。
5、Mysql和Oacle是怎么分页的?
答:Mysql分页:
select * from table_name t limit 5,10;
Oracle分页:
Select * from (
Select A.*,Rownum RN from (
Select * from table_name
) A where Rownum <= 40
) where RN >= 21
6、函数和存储过程有什么区别?
答:1)函数标识符为function,存储过程为procedure;
2)函数中有返回值,而存储过程没有返回值;
3)函数有返回值类型,调用时,除在select中,必须将返回值赋给变量;过程无返回值,不能将结果直接赋给变量;
4)函数可以在select语句中直接使用,而过程不能。
7、数据库优化有哪些方法?
答:(1)sql层面优化;
(2)分库分表;
(3)用view和存储过程处理复杂逻辑
8、Mysql中索引有哪些类型?
答:普通索引(INDEX):最基本的索引,没有任何限制
唯一索引(UNIQUE):与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值。
主键索引(PRIMARY):它是一种特殊的唯一索引,不允许有空值。
全文索引(FULLTEXT ):仅可用于 MyISAM 表, 用于在一篇文章中,检索文本信息的, 针对较大的数据,生成全文索引很耗时好空间。
组合索引:为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则。
MySQL目前主要有以下几种索引类型:FULLTEXT,HASH,BTREE,RTREE。
9、Redis和Memcached缓存原理
答:Redis运行原理:
参考http://blog.csdn.net/jinfeiteng2008/article/details/53711752
搭建redis环境:
参考http://www.cnblogs.com/liuhongfeng/p/4704443.html
使用redis参考http://www.cnblogs.com/liuhongfeng/p/5033559.html
1、单态模式
单态设计模式,又称单例模式,是指针对某个类在程序运行期间只存在一个实例对象
// 数据产生器, 该类的实例对象负责产生数字 发号码
// 需求 针对某个类在程序的整个运行期间只能有一个实例对象
/*
* 单态设计模式,又称单例模式 针对某个类在程序的整个运行期间只能有一个实例对象
* 实现步骤
* 1 将类的构造方法声明为私有
* 2 定义一个成员变量记住该类的一个实例对象,
* 由于要被静态方法调用,所以变量要声明为static
* 由于不想被外界改变,所以变量要声明为 private
* 3 提供共有的方法返回类的实例对象(之前定义的变量)
* 由于该类无法实例化,调用者只能通过 类名.方法名的方式来访问,所以该方法要声明为 static
*/
public class NumberProcessor {
private int num = 0;
// 定义成员变量记住类的单例,不允许直接访问
private static NumberProcessor instance = new NumberProcessor();
// 不让外界new实例对象
private NumberProcessor() {}
// 提供一个方法 返回该类的实例对象
public static NumberProcessor getInstance() {
return instance;
}
// 发号码
public int makeNumber() {
num++;
return num;
}
}
// 单例的实现方式二:
public class NumberProcessor {
private int num = 0;
// 定义成员变量记住类的单例,不允许外界修改变量,但可以访问
private final static NumberProcessor INSTANCE = new NumberProcessor();
// 不让外界new实例对象
private NumberProcessor() {}
// 发号码
public int makeNumber() {
num++;
return num;
}
}
懒汉(饱汉)模式单例:
//懒汉式单例类.会延迟加载,在第一次调用的时候才实例化自己,线程不安全
public class Singleton {
private Singleton() {}
private static Singleton single=null;
//静态工厂方法
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
饿汉(饥汉)模式单例:
//饿汉式单例类.在类初始化时,已经自行实例化,线程安全
public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance() {
return single;
}
}
静态代理:由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
动态代理:动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
2、模板方法设计模式
定义抽象父类作为模板,其中定义模板方法(方法需要final),在模板方法中调用其他功能方法,实际上就是规定功能方法的一个执行顺序,在模板类中功能方法不实现,声明为abstract抽象的
所有子类都针对模板类进行继承,实现所有的功能方法,由于不能修改模板方法,所以每个子类的功能方法的调用顺序都是固定的,所有的子类的功能方法调用顺序要想被修改,只需修改模板方法即可
/**
* 模板方法设计模式:
* 定义抽象的父类作为模板,在父类中定义模板方法(此方法要final,不允许子类重写)
* 在模板方法中规定其他方法(抽象方法,留给子类实现)的调用顺序,以保证整个程序的正常运行。
*
* 不同的子类继承模板父类,实现所有的抽象方法,继承父类的模板方法,
* 在功能调用时针对模板方法进行调用,子类实现的所有方法都会按照一种事先定义好的流程来运行
*
*/
// 打印的模板 抽象的父类 指定打印的流程
public abstract class AbstractPrint {
// 模板方法,规定了其他方法的调用顺序
public final void run() {
// 开启打印机
this.start(); // this 指向子类是对象,所以会调用子类的start方法
// 打印
this.print();
// 关闭打印机
this.close();
}
public abstract void start();
public abstract void print();
public abstract void close();
}
public class StringPrint extends AbstractPrint {
public void start() {
System.out.print("<<");
}
public void print(){
System.out.print("hello");
}
public void close(){
System.out.println(">>");
}
}
public class Demo1 {
public static void main(String[] args) {
StringPrint sp = new StringPrint();
sp.run();
}
}
3、策略模式
程序提供的功能需要依赖将来的调用者实现,在程序中只规定算法,不针对算法进行实现
可以将需要的功能定义为接口中的方法,并对外声明,实现方法需要传入接口类型,此时调用者为了调用我们的功能
必须要实现接口,创建实现类实例传入
调用者实现接口的事情是被程序的设计者所强制的
// 数字打印机
public class NumberPrinter {
// 持有数字
private int[] arr;
public NumberPrinter(int[] arr) {
this.arr = arr;
}
public void print(NumberFilter filter) {
for(int i=0; i<arr.length; i++) {
int num = arr[i];
if(filter.accept(num)) {
System.out.print(num + ",");
}
}
}
}
public interface NumberFilter {
boolean accept(int num);
}
/**
* 设计模式之策略模式
* 在程序的功能实现过程中,我们只规定算法名称,具体的算法留给将来的程序实现
* 在一个程序中提供的功能得以实现需要借助调用者的帮忙,并且是强制性的,此时可以在方法的参数中定义接口,让调用者来实现
*/
public class Demo1 {
public static void main(String[] args) {
int[] arr = {1,4,5687,34,23,456,67};
NumberPrinter np = new NumberPrinter(arr);
np.print(new NumberFilter() {
public boolean accept(int num) {
if(num>50)
return true;
return false;
}
});
}
}
1、二分算法的原理?
答:二分算法,也称折半查找法。原理:将n个元素分成个数大致相同的两半,取a[n/2]与预查找的x作比较,如果x=a[n/2]则找到x,算法终止;如果x< a[n/2],则我们只需要在数组a的左半部分继续搜索x(假设数组呈升序排列);如果x> a[n/2],则只需要在数组a的右半部分查找x。
Public static int BinarySearch(int[] array,int key){
Int left=0;
Int right=array.length-1;
Int middle=0;
Whie(left<right){
Middle=(left+right)/2;
Int middlevalue=array[middle];
If(middlevalue<key){
Left=middle+1;
}else if(middlevalue>key){
Right=middle-1;
}else{
Return middle;
}
}
Return –(left+1);
}
2、冒泡排序算法原理?
答:依次比较相邻的两个元素,如果第一个数比第二个数大,就交换两个数的位置。每轮比较之后,最值出现在头角标位置。如此循环,n轮过后,就形成一个有序的数列;
public class BubbleSort{
public void sort(int[] a){
int temp = 0;
for (int x = 0;x < a.length - 1; x++){
for (int y = 0; y < a.length -x- 1;y++){
if (a[y] < a[y+1]){
temp = a[y];
a[y] = a[y+ 1];
a[y + 1] = temp;
}
}
}
}
}
3、选择排序算法原理?
答:以一个角标上的元素为主,依次与其他各元素进行比较,满足条件,就交换位置。第一次循环结束后,最值出现在头角标位置上。以此类推,再用该方式进行下一轮循环,直至形成有序数列。
public class SelectSort{
public void sort(int[] a){
int temp = 0;
for (int x = 0; x < a.length - 1; x++){
for (int y = x++; y < a.length; y++){
if (a[x] > a[y]){
temp = a[x];
a[x] = a[y];
a[y] = temp;
}
}
}
}
}
4、递归之奶牛问题
public class Demo2 {
/**
* 奶牛问题: 农场有一头奶牛,从第三年开始每一年生一头奶牛,问10年后农场中有多少头奶牛
*
* 汉罗塔 :
*/
public static void main(String[] args) {
int year = 10;
int cowNum = getCowNum(year);
System.out.println(cowNum);
}
// 求一头牛在指定的年份内到底能产生多少头牛,包括自己
public static int getCowNum(int maxAge) {
int cowNum = 1;
// 计算能生多少头牛
for(int i=3; i<=maxAge; i++) {
// 每年生一头, 计算出生的这头牛能产生多少牛,包括自己
cowNum += getCowNum(maxAge-i);
}
return cowNum;
}
}
package cn.itcast.demo2;
public class Demo3 {
public static void main(String[] args) {
// 面向对象解决奶牛问题
new Cow(7);
System.out.println(Cow.getCowNum());
}
}
class Cow {
private int age;
private static int cowNum; // 记住内存中 Cow 实例对象的数量,多少头牛,该变量要静态
private int maxAge;
public Cow(int maxAge) {
// 新创建一个 Cow 对象 相当于生了一头牛 让 cowNum ++
cowNum++;
this.maxAge = maxAge;
while(this.age<maxAge) {
this.grow();
}
}
public void grow() {
this.age++;
// 每长一岁就生一头牛,前提是3岁以后
if(this.age>=3) {
new Cow(this.maxAge-this.age);
}
}
public static int getCowNum() {
return cowNum;
}
}
5、猴子运香蕉问题:一只猴子旁边有100根香蕉,猴子距离家50米,猴子一次顶多搬50根香蕉,但猴子每走一米就要吃掉一根香蕉。问猴子最多能拿多少根香蕉回家?
答:16根。应注意往回走时,也吃香蕉。
先拿50根,走一米放下,拿一根往回走,再取剩下的50根,与原来的放在一起,
拿 50根走一米,放下,拿一根往回走,再取剩下的47根,与原来的放在一起,
拿50根走一米,放下,拿一根往回走,再取剩下的44根,与......
每走一米吃3根,16米后吃48根,还剩52根,
直接拿50根往家走,不用回来,剩下的34米吃34根,
最后拿到家的只有16根。