1.JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么?
JSP是Servlet技术的扩展,本质上是Servlet的简易方式,更强调应用的外表表达。JSP编译后是"类servlet"。Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet主要用于控制逻辑,是前后端交互的一个容器。
2.Static变量是什么含义
static是静态变量,就是变量值不随函数执行结束而消失,下次调用同一函数时,上次所赋予的值仍存在。
3.垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收
对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。
4.说出Servlet的生命周期
Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。
5.HashMap与TreeMap的区别?
解答:HashMap通过hashcode对其内容进行快速查找,HashMap是“无序”的,也就是说不能保证插入顺序。但是,HashMap其实也是有序的,一组相同的key-value对,无论他们插入的顺序是什么样的,遍历时,顺序都是一致的。而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。
HashMap无序,
LinkedHashMap有序,输出时保持数据存入时的顺序
6.请说出ArrayList,Vector, LinkedList的存储性能和特性
解答:ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
7.事务是什么?有哪些属性,并简要说明这些属性的含义。
解答:事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。
事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。
原子性(atomicity):一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
一致性(consistency):在事务开始之前和事务结束以后,数据库的完整性约束(数据完整性约束指的是为了防止不符合规范的数据进入数据库)没有被破坏。
隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability):持续性也称永久性(permanence),指一个事务一旦提交则不可逆,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
8.重载(overload)和重写(override)的区别?重载的方法能否根据返回类型进行区分?
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求。
方法重载的规则:
- 方法名一致,参数列表中参数的顺序,类型,个数不同。
- 重载与方法的返回值无关,存在于父类和子类,同类中。
- 可以抛出不同的异常,可以有不同修饰符。
方法重写的规则:
- 参数列表必须完全与被重写方法的一致,返回类型必须完全与被重写方法的返回类型一致。
- 构造方法不能被重写,声明为 final 的方法不能被重写,声明为 static 的方法不能被重写,但是能够被再次声明。
- 访问权限不能比父类中被重写的方法的访问权限更低。
- 重写的方法能够抛出任何非强制异常(UncheckedException,也叫非运行时异常),无论被重写的方法是 否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以
9.==和 equals 的区别?
equals 和== 最大的区别是一个是方法一个是运算符。
==:如果比较的对象是基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的地址值是否相等。
equals():用来比较方法两个对象的内容是否相等。
注意:equals 方法不能用于基本数据类型的变量,如果没有对 equals 方法进行重写,则比较的是引用类型的变量所指向的对象的地址。
10.Object有哪些公用方法
clone: 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
equals :在Object中与==是一样的,子类一般需要重写该方法。
hashCode :该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
getClass: final方法,获得运行时类型
wait :使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。 wait() 方法一直等待,直到获得锁或者被中断。 wait(long timeout) 设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生
- 1、其他线程调用了该对象的notify方法。
- 2、其他线程调用了该对象的notifyAll方法。
- 3、其他线程调用了interrupt中断该线程。
- 4、时间间隔到了。
- 5、此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
notify: 唤醒在该对象上等待的某个线程。
notifyAll: 唤醒在该对象上等待的所有线程。
toString: 转换成字符串,一般子类都有重写,否则打印句柄。
11.JDK8中的HashMap
- 当向 HashMap 中 put 一对键值时,它会根据 key的 hashCode 值计算出一个位置, 该位置就是此对象准备往数组中存放的位置。
- 如果该位置没有对象存在,就将此对象直接放进数组当中;如果该位置已经有对象存在了,则顺着此存在的对象的链开始寻找(为了判断是否是否值相同,map不允许<key,value>键值对重复), 如果此链上有对象的话,再去使用 equals方法进行比较,如果对此链上的每个对象的 equals 方法比较都为 false,则将该对象放到数组当中,然后将数组中该位置以前存在的那个对象链接到此对象的后面。
- JDK8中采用的是位桶+链表/红黑树(有关红黑树请查看红黑树)的方式,也是非线程安全的。当某个位桶的链表的长度达到某个阀值的时候,这个链表就将转换成红黑树。
JDK8中,当同一个hash值的节点数不小于8时,将不再以单链表的形式存储了,会被调整成一颗红黑树(上图中null节点没画)。这就是JDK7与JDK8中HashMap实现的最大区别。
12.为什么要使用 PreparedStatement?
- PreparedStatement接口继承 Statement,PreparedStatement 实例包含已编译的 SQL
语句,所以其执行速度要快于 Statement 对象。 - 作 为 Statement 的 子 类 ,PreparedStatement 继 承了Statement 的 所 有 功 能。 三 种 方法 execute、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数
- 在 JDBC 应用中,在任何时候都不要使用 Statement,原因:代码的可读性和可维护性.Statement 需要不断地拼接,而 PreparedStatement 不会。
- PreparedStatement 尽最大可能提高性能.DB有缓存机制,相同的预编译语句再次被调用不会再次需要编译。最重要的是极大地提高了安全性.Statement 容易被 SQL 注入,而PreparedStatementc 传入的内容不会和 sql 语句发生任何匹配关系。
13.Spring控制器接受请求参数的常见方式有哪几种。
- 通过实体bean接收请求参数
- 通过处理方法的形参接收请求参数
- 通过HTTPServletRequest接收请求参数
- 通过@PathVariable接收URL中的请求参数
- 通过@RequestParam接收请求参数
- 通过@ModeAttribute接收请求参数
14.throw 和 throws 的区别
throw:
- throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。
- throw 是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行 throw 一定是抛出了某种异常。
throws:
- throws 语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理。
- throws 主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型。
- throws 表示出现异常的一种可能性,并不一定会发生这种异常。
- Java中final,finalize和finally的区别
final关键字可以用于类,方法,变量前,用来表示该关键字修饰的类,方法,变量具有不可变的特性。
(1)final关键字用于基本数据类型前:这时表明该关键字修饰的变量是一个常量,在定义后该变量的值就不能被修改。
(2)final关键字用于方法声明前:这时意味着该方法时最终方法,只能被调用,不能被覆盖,但是可以被重载。
(3)final关键字用于类名前:此时该类被称为最终类,该类不能被其他类继承。
finalize方法来自于java.lang.Object,用于回收资源。
可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清除对象之前调用。
在实际应用中,不要依赖使用该方法回收任何短缺的资源,这是因为很难知道这个方法什么时候被调用。
finally当代码抛出一个异常时,就会终止方法中剩余代码的处理,并退出这个方法的执行。假如我们打开了一个文件,但在处理文件过程中发生异常,这时文件还没有被关闭,此时就会产生资源回收问题。
对此,java提供了一种好的解决方案,那就是finally子句,finally子句中的语句是一定会被执行的,所以我们只要把前面说的文件关闭的语句放在finally子句中无论在读写文件中是否遇到异常退出,文件关闭语句都会执行,保证了资源的合理回收。
16. String,StringBuffer和StringBuilder区别
三者共同之处:都是final类,不允许被继承,主要是从性能和安全性上考虑的,因为这几个类都是经常被使用着,且考虑到防止其中的参数被参数修改影响到其他的应用。
StringBuffer是线程安全,可以不需要额外的同步用于多线程中;
StringBuilder是非线程安全,运行于多线程中就需要使用着单独同步处理,但是速度就比StringBuffer快多了;
StringBuffer与StringBuilder两者共同之处:可以通过append、indert进行字符串的操作。
StringBuilder只实现了两个接口Serializable、CharSequence,相比之下String的实例可以通过compareTo方法进行比较,其他两个不可以。
如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的。
但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。(一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞)
总结一下
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
17.创建线程有哪些方式?怎么启动一个线程?请说明。
创建线程:
继承 Thread 类、实现 Runnable 接口、应用程序可以使用 Executor 框架来创建线程池
实现 Runnable 接口这种方式更受欢迎,因为这不需要继承 Thread 类。在应用设计中已经继承了别的对象的情况下,这需要多继承(而 Java 不支持多继承),只能实现接口。同时,线程池也是非常高效的,很容易实现和使
启动线程:
在创建线程的方法里:New一个线程实例对象、通过t.start();方法来启动线程
18.什么是单例模式?
单例模式有以下特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
目的:
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。
单例模式有两种实现方式
懒汉式、饿汉式、使用容器实现单例模式、静态内部类、枚举单例、双重校验锁
19.列举你用过的几种表连接方式?
一.外连接:
外连接包括三种,分别是左外连接、右外连接、全外连接。
对应的sql关键字:LEFT/RIGHT/FULL OUTER JOIN,通常我们都省略OUTER关键字,写成LEFT/RIGHT/FULL JOIN。
在左、右外连接中都会以一种表为基表,基表的所有行、列都会显示,外表如果和条件不匹配则所有的外表列值都为NULL。
全外连接则所有表的行、列都会显示,条件不匹配的值皆为NULL。
二. 内连接:
内连接是用比较运算符比较要连接的列的值的连接,不匹配的行不会被显示。sql关键字JOIN 或者INNER JOIN,通常我们写成JOIN
三.交叉连接:
概念:没有where条件的交叉连接将产生连接表所涉及的笛卡尔积。即TableA的行数TableB的行数的结果集。(TableA 3行TableB 3行=9行)
20.请简要说明http协议属于网络层的哪一层?状态码200,302,404,500分别代表什么含义?
应用层
200:确定。客户端请求已成功
302:暂时性重定向
404:未找到文件或目录
500:服务器内部错误
21.TCP与UDP的差别
TCP协议是有连接的,有连接的意思是开始传输实际数据之前TCP的客户端和服务器端必须通过三次握手建立连接,会话结束之后也要结束连接。而UDP是无连接的
TCP协议保证数据按序发送,按序到达,提供超时重传来保证可靠性,但是UDP不保证按序到达,甚至不保证到达,只是努力交付,即便是按序发送的序列,也不保证按序送到。
TCP协议所需资源多,TCP首部需20个字节(不算可选项),UDP首部字段只需8个字节。
TCP有流量控制和拥塞控制,UDP没有,网络拥堵不会影响发送端的发送速率
TCP是一对一的连接,而UDP则可以支持一对一,多对多,一对多的通信。
TCP面向的是字节流的服务,UDP面向的是报文的服务。
22.简述TCP的三次握手与四次挥手
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器 进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED状态,完成三次握手。
第一次挥手:客户端向服务器端发送断开 TCP 连接请求的 [FIN,ACK] 报文,在报文中随机生成一个序列号 SEQ=x,表示要断开 TCP 连接
第二次挥手:当服务器端收到客户端发来的断开 TCP 连接的请求后,回复发送 ACK 报文,表示已经收到断开请求。回复时,随机生成一个序列号 SEQ=y。由于回复的是客户端发来的请求,所以在客户端请求序列号 SEQ=x的基础上加 1,得到 ACK=x+1
第三次挥手:服务器端在回复完客户端的 TCP 断开请求后,不会马上进行 TCP 连接的断开。服务器端会先确认断开前,所有传输到客户端的数据是否已经传输完毕。确认数据传输完毕后才进行断开,向客户端发送 [FIN,ACK] 报文,设置字段值为 1。再次随机生成一个序列号 SEQ=z。由于还是对客户端发来的 TCP 断开请求序列号 SEQ=x 进行回复,因此 ACK 依然为 x+1
第四次挥手:客户端收到服务器发来的 TCP 断开连接数据包后将进行回复,表示收到断开 TCP 连接数据包。向服务器发送 ACK 报文,生成一个序列号 SEQ=x+1。由于回复的是服务器,所以 ACK 字段的值在服务器发来断开 TCP 连接请求序列号 SEQ=z 的基础上加 1,得到 ACK=z+1
23.线程与进程的差异:
进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
进程中可以包括有多个线程,也可以只有一个线程,进程与进程之间是相对比较独立的。
在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)
24.线程间通信/进程间通信的方法
线程间: 共享内存:线程之间共享程序的公共状态,线程之间通过读-写内存中的公共状态来隐式通信。(volatile共享内存)
消息传递:线程之间没有公共的状态,线程之间必须通过明确的发送信息来显示的进行通信。( wait/notify和join等待通知方式)
管道流: 管道输入/输出流的形式
进程间:进程间通信(IPC,InterProcess Communication)的主要方式包括:管道、FIFO、消息队列、信号量
25.数据库的范式
第一范式:属于第一范式关系的所有属性都不可再分,即数据项不可分。强调原子性
第二范式:第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。如下面这两个表所示的设计就是一个满足第三范式的数据库表。
26.Spring框架
Spring是一个开发JavaEE应用程序的轻量级的一站式框架。包含了许多模块
模块:Spring AOP, Spring DAO, Spring MVC ,Spring Core等
Spring Core:
1. IOC Inverse Of Controll 控制反转
传统的java对象的创建方式,是以new的方式在程序中硬编码创建的。所谓的“反转”指的是,对象的创建方式不是由程序员通过编码方式创建,而是通过spring容器创建。由容器创建对象。控制反转就是容器托管对象。比如,servlet实例就是由web容器托管的对象,容器通过生命周期管理servlet实例的。
2. DI Dependency Injection 依赖注入
依赖:应用中的对象与对象 或 组件与组件之间关联关系。
依赖注入:由容器对依赖关系进行初始化赋值,装配对象,并且管理这些对象的生命周期
Spring AOP:
(1)AOP Aspect Oriented Programming 面向切面编程,其实就是拦截器。
(2)JavaEE应用中,常见的“拦截”的技术:
原生平台中的Filter, 过滤器。过滤的是一切可访问的资源,包括,页面,图片,样式,servle/jsp。
Spring中的AOP, 主要是拦截业务层的方法。对业务方法的功能增强。
MVC框架,也提供了拦截器。拦截的是控制器,主要是action(Struts2), handler(springmvc).
(3) 拦截的概念:对目标对象的代理,并进行功 的增强。简单来说,就是增强功能。
对于“共性”的问题,如果OOP解决不了的,可以使用AOP来解决“通用性”的问题。AOP是对OOP的补充的作用。也就是解决通用性问题。作用:降低耦合度。
(4)aop编程的术语
aspect 切面 对共性问题的抽象 , 拦截器类
pointcut 切入点 被拦截的方法
advice 通知,功能增强, 增强的方式:前置增强,后置增强,环绕增强,异常增强,最终增强。
spring的四个特点:
非侵入式:Spring框架的API不会在业务逻辑上出现,既业务逻辑是POJO。
容器:Spring作为一个容器,可以管理对象的生命周期、对象与对象之间的依赖关系。
IOC:既控制反转,容器托管对象
AOP:既面向切面编程(Aspect Orient Programming)。是一种编程思想,是面对对象编程oop的补充和完善,因为OOP 允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能;AOP 技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
Spring 的通知是什么?有哪几种类型?
通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过 SpringAOP 框架触发的代码段。
- before:前置通知,在一个方法执行前被调用。
- after: 在方法执行之后调用的通知,无论方法执行是否成功。
- after-returning: 仅当方法成功完成后执行的通知。
- after-throwing: 在方法抛出异常退出时执行的通知。
- around: 在方法执行之前和之后调用的通知。
Spring 支持的几种 bean 的作用域。
Spring 框架中的单例 bean 不是线程安全的。
Spring 框架支持以下五种 bean 的作用域:
singleton : bean 在每个 Spring ioc 容器中只有一个实例。
prototype:一个 bean 的定义可以有多个实例。
request:每次 http 请求都会创建一个 bean,该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。
session :在一个 HTTP Session 中 , 一 个 bean 定义对应一个实例 。该作用域仅在基于 web 的Spring ApplicationContext 情形下有效。
global-session:在一个全局的 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的Spring ApplicationContext 情形下有效。
缺省的 Spring bean 的作用域是 Singleton。
spring bean的生命周期
spring中定义bean的方式
springboot自动装配原理
springboot是通过main方法下的SpringApplication.run方法启动的,启动的时候他会调用refshContext方法,先刷新容器,然后根据解析注解或者解析配置文件的形式注册bean,而它是通过启动类的SpringBootApplication注解进行开始解析的,他会根据EnableAutoConfiguration.class对象开启自动化配置,里面有个核心注解@Import({AutoConfigurationImportSelector.class}),根据loadFanctoryNames根据classpash路径以MATA-INF/spring.factorces下面以什么什么EnableAutoConfiguration开头的key去加载里面所有对应的自动化配置,他并不是把这一百二十多个自动化配置全部导入,在他每个自动化配置里面都有条件判断注解,先判断是否引入相互的jar包,再判断容器是否有bean再进行注入到bean容器
27.SpringMVC:Spring MVC是Spring框架的一个模块,是基于MVC模式的web框架,采用前端控制器设计模式
主要核心组件:
DispatcherServlet 前端控制器
HandlerMapping 处理器映射器
HandlerAdapter 处理器适配器
Handler 也就是Controller
ViewResolver 视图解析器
Interceptor 拦截器
工作流程:
1.用户发送请求至前端控制器DispatcherServlet
2.DispatcherServlet收到请求调用处理器映射器HandlerMapping。
3.处理器映射器根据请求url找到具体的处理器,生成处理器执行链Hand