java面试题1

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

  1. 当向 HashMap 中 put 一对键值时,它会根据 key的 hashCode 值计算出一个位置, 该位置就是此对象准备往数组中存放的位置。
  2. 如果该位置没有对象存在,就将此对象直接放进数组当中;如果该位置已经有对象存在了,则顺着此存在的对象的链开始寻找(为了判断是否是否值相同,map不允许<key,value>键值对重复), 如果此链上有对象的话,再去使用 equals方法进行比较,如果对此链上的每个对象的 equals 方法比较都为 false,则将该对象放到数组当中,然后将数组中该位置以前存在的那个对象链接到此对象的后面。
  3. 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找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
4.DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
5.执行处理器Handler(Controller,也叫页面控制器)。
6.Handler执行完成返回ModelAndView
7.HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
8.DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9.ViewReslover解析后返回具体View
10.DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
11.DispatcherServlet响应用户。

28.shiro安全性框架:(用户认证 登录 资源授权 权限管理)

可以应用于任何的应用系统中,不依赖于spring框架。
可以轻松的完成:身份认证、授权、加密、会话管理等功能
首先shiro工作流程中又三个重要的组件,分别是Subject,SecurityManager,以及Realm。
先来介绍Subject,即为主体也就相当于目前操作系统的用户直观来说就相当于目前登录的用户。这里Subject主要是用来检测用户的登录,登录完之后就主要将工作交给SecurityManager来完成
其次就是SecurityManager主要来检测目前的用户Subject的一系列的安全操作,比如说当前用户所具备的权限,以及该用户的角色是哪一层级的,在用户执行一系列操作的时候进行授权,避免越权的操作。
之后就是Realm,他主要就是负责与数据库交互,就比如说SecurityManager来检测用户的权限是,就需要Realm从数据库中取出该用户的权限以及角色信息,之后才能方便SecurityManager来进行授权的操作。

29.数据库索引:

1.聚集索引(主键索引):在数据库里面,所有行数都会按照主键索引进行排序。
2.非聚集索引:就是给普通字段加上索引。
3.联合索引:就是好几个字段组成的索引,称为联合索引。

30.数据库优化:

少让表之间关联过于复杂,比如某些表多关联查询的时候,可以把经常展示的信息集中放到一张表中,减少关联查询。就是能分开写的语句就分开写,不要一次性就解决,这样对效率来说是很大的开销的
尽量避免在where子句中对字段进行函数或表达式操作
尽量避免在索引过的字符数据中,使用非打头字母所有
取别名
创建索引

31.session和cookie

1,Cookie(属于客户端):数据存储在客户端本地,减少服务器端的存储的压力,安全性不好,客户端可以清除cookie;cookie只允许存储字符串类型的数据;只能存储少量的数据;如果不设置持久化保存(cookie.setMaxAge();),当浏览器被关闭之后既这一次绘画结束之后,cookie信息会自动被删除
2,Session(属于服务器端):将数据存储到服务器端,可以存储Object类型的数据,安全性相对好,增加服务器的压力;session的生命周期是一次会话,在这个会话期间,存储在它里面的数据都可以访问。当客户端停止对服务器的操作,Session在服务器中默认的停留时间,30分钟(从你不再操作服务器开始)
3,联系:session运行依赖于sessionID,而sessionID是存储在cookie中的,如果在浏览器中禁用了cookie,那session也失效了

32.Servlet的两个域对象

1,ServletContext:上下文的域对象,生命周期很长(只要服务器tomcat不关闭,那么数据一直存在)
2,Request:请求的域对象,生命周期很短(一次请求之间:客户端向服务器端发送一个请求,服务器给客户端一个响应,这一过程称为一次请求的过程)

33.JSP三大指令

1.page指令:语法格式:<%@page attribute1=“value1” attribute2=“value2”…%>
2.include指令:语法格式:<%@ include file=“url”%>,利用include可以将另外一个文件的内容放在当前的JSP页面中,可以使用多个include指令,并且可以在任意位置,用于多个页面相同元素做成一个文件,再用include指令在其他页面有使用它的位置使用,节约大量代码量。
3.taglib指令:语法格式:<%@ taglib (uri=“tagLibraryURI” | tagdir=“tagDir”) prefix=“tagPrefix” %>,uri属性用于对自定义标签进行命名,可以是相对路径或绝对路径,prefix指定了标签的前缀。

34.jsp的9大内置对象

1,out:用于页面输出
2,request:得到用户请求信息
3,response:服务器向客户端的回应信息
4,config:服务器配置,可以取得初始化参数
5,session:所有用户的状态相关的数据
6,application:所有用户的共享信息
7,page:指当前页面转换后的Servlet类的实例
8,pageContext:JSP的页面容器
9,exception:表示JSP页面所发生的异常,注意:(在错误页(isErrorPage)中才起作用)

四大域对象:
1,request:HttpServletRequest,一次请求
2,session:HttpSession,一次会话
3,application:ServletContext,整个web应用
4,pageContext:PageContext,当前jsp页面范围=
37.Hibernate
Hibernate是一个完整的ORM框架(对象关系映射),主要映射对象模型,映射数据库表,对象间的关联关系(一对一,一对多,多对多)
临时状态 当使用new实例化出来的对象,该对象还没在hibernate容器中管理
持久状态 该对象是由hibernate容器管理的。对象与数据库的数据一一对应。也称为“托管状态”
游离状态 持久状态的对象脱离容器的管理,也称为“脱管状态”
Hibernate主要查询技术:HQL查询,QBC查询,原生SQL查询

35. Mybatis和Hibernate框架的对比

mybatis查询语言就是sql,hibernate查询语言hql语句。
ORM方面的区别:hibernate是一个完整的ORM框架,映射的是整个应用的实体模型,自动加载实体间的关联关系。mybatis是一个非完整的ORM框架,映射的是sql语句,sql是定义在外部xml映射文件中。

36.JPA 概述

  1. Java Persistence API(Java 持久层 API):用于对象持久化的 API
  2. 作用:使得应用程序以统一的方式访问持久层
  3. 前言中提到了 Hibernate,那么JPA 与 Hibernate究竟是什么关系呢:
    1)JPA 是 Hibernate 的一个抽象,就像 JDBC 和 JDBC 驱动的关系
    2)JPA 是一种 ORM 规范,是 Hibernate 功能的一个子集 (既然 JPA 是规范,Hibernate 对 JPA 进行了扩展,那么说 JPA 是 Hibernate 的一个子集不为过)
    3)Hibernate 是 JPA 的一个实现
  4. JPA 包括三个方面的技术:
    1)ORM 映射元数据,支持 XML 和 JDK 注解两种元数据的形式
    2)JPA 的 API
    3)查询语言:JPQL

37.sleep和wait方法

sleep方法执行时不会释放锁,也不一定要放在同步方法或同步块中,属于 Thread 类;
wait/notify 必须在同步方法中,会释放锁,属于 Object 类

38.接口

接口里可以定义变量,并且默认加上public static final,所有变量不能修改;
接口只能被public修饰,或者不加修饰符;
外部类不能被private修饰,内部类可以;
如果一个类中有一个方法时抽象类,那么这个类也必须是抽象类,抽象类中也可以有普通方法;
抽象类不能被实例化,但可以写出匿名内部类;
Collection时集合框架的顶层接口;
HashMap允许null键或值,Hashtable不允许null键或值;
构造方法可以被重载,不能被重写,可以被声明为private;
abstract不能修饰字段;

39.java中两种异常类型是什么,有什么区别

Java中有两种异常:受检查的(checked)异常和不受检查的(unchecked)异常。不受检查的异常不需要在方法或者是构造函数上声明,就算方法或者是构造函数的执行可能会抛出这样的异常,并且不受检查的异常可以传播到方法或者是构造函数的外面。相反,受检查的异常必须要用throws语句在方法或者是构造函数上声明。

40.数据库连接池

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。

41. mybatis工作原理

读取mybatis的配置文件
加载映射文件
构建SqlSessionFactory会话工厂
通过SqlSessionFactory加载SqlSession会话对象
通过 sqlsession 执行数据库操作
调用 session.commit()提交事务
调用 session.close()关闭会话

为什么要用
1、简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。

2、灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。

3、解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。

4、提供映射标签,支持对象与数据库的orm字段关系映射。

5、提供对象关系映射标签,支持对象关系组建维护。

Mybatis 中一级缓存与二级缓存

  1. 一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或close 之后,该 Session 中的所有 Cache 就将清空。

  2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为Mapper(Namespace),并且可自定义存储源,如 Ehcache。启动二级缓存:在 mapper 配置文件中:。
    二级缓存可以设置返回的缓存对象策略:。当 readOnly="true"时,表示二级缓存返回给所有调用者同一个缓存对象实例,调用者可以 update 获取的缓存实例,但是这样可能会造成其他调用者出现数据不一致的情况(因为所有调用者调用的是同一个实例)。当readOnly="false"时,返回给调用者的是二级缓存总缓存对象的拷贝,即不同调用者获取的是缓存对象不同的实例,这样调用者对各自的缓存对象的修改不会影响到其他的调用者,即是安全的,所以默认是 readOnly=“false”;

mybatis的优缺点

Mybait的优点:
(1)简单易学,容易上手(相比于Hibernate) 基于SQL编程;
(2)JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;
(3)很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持,而JDBC提供了可扩展性,所以只要这个数据库有针对Java的jar包就可以就可以与MyBatis兼容),开发人员不需要考虑数据库的差异性。
(4)提供了很多第三方插件(分页插件 / 逆向工程);
(5)能够与Spring很好的集成;
(6)MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,解除sql与程序代码的耦合,便于统一管理和优化,并可重用。
(7)提供XML标签,支持编写动态SQL语句。
(8)提供映射标签,支持对象与数据库的ORM字段关系映射。
(9)提供对象关系映射标签,支持对象关系组建维护。

MyBatis框架的缺点:
(1)SQL语句的编写工作量较大,尤其是字段多、关联表多时,更是如此,对开发人员编写SQL语句的功底有一定要求。
(2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

42.计算一个数字的立方根,不使用库函数

public class demo1 {
    public static double getCubeRoot(double input)
    {
        double min = 0;
        double max = input;
        double mid = 0;

        // 注意,这里的精度要提高一点,否则某些测试用例无法通过
        while ((max - min) > 0.001)
        {
            mid = (max + min) / 2;
            if (mid * mid * mid > input)
                max = mid;
            else if (mid * mid * mid < input)
                min = mid;
            else
                return mid;
        }
        return max;
    }

    public static void main(String[] args) {
        Scanner s=new Scanner(System.in);
        double input =s.nextDouble();
        double result=getCubeRoot(input);
        System.out.printf("%.1f\n",result);
    }
}

43.产生死锁的原因?如何避免

死锁的定义:所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。
在这里插入图片描述

如何避免死锁

1.加锁顺序(线程按照一定的顺序加锁)
2.加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)

44.对注解的理解

Java的注解有三类,分别是:元注解,自定义注解,jdk自带的注解。
元注解是指在定义一个注解的时候,必须要使用元注解进行标注,@Target,@Retention,@Documented,@Inherited,这四个是java的元注解;
jdk自带的注解是java已经定义好的注解,比如@override。
自定义注解是开发者定义的注解

45.对泛型的理解

泛型的作用基本就是参数化数据类型,目的是为了安全

泛型的优点

1,类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于 程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。

2,消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。

46.设计模式

工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式、适配器模式、桥接模式、过滤器模式、组合模式、装饰器模式、外观模式、享元模式、代理模式、责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式

47.按位与和逻辑与的区别

按位与:&:无论如何都会把两边都运算一次
逻辑与:&&:也叫做短路与 因为只要当前项为假,它就不往后判断了,直接认为表达式为假

48.设计算法实现回文数

boolean isPalindromeNumber1(long num) {
        String numStr = num + "";
        int length = numStr.length();
        String str = "";
        for (int i = 0; i < length; i++) {
            str = numStr.charAt(i) + str;
        }
        if(numStr.equals(str)){
            return true;
        }else{
            return false;
        }
}

49.Linux命令

a)查看当前目录下文件名含有.log的文件列表
find . -type f -name "*.log
b)重命名文件
mv A B
c)查看tomcat进程情况
ps -ef|grep tomcat
d)压缩/解压
tar解压:tar zxvf filename.tar
tar压缩:tar czvf filename.tar dirname
zip解压:unzip filename.zip
zip压缩:zip filename.zip dirname
e)查看系统当前负荷(cpu,内存等)
top命令查看cpu情况
free命令查看内存情况
netstat -nultp(此处不用加端口号):该命令是查看当前所有已经使用的端口情况
netstat -anp |grep 端口号:查看具体的端口号

java输入一行字符,统计英文字母,数字和其他字符

public class demo1 {
    public static void main(String[] args) {
        int letterSum = 0;
        int blankSum = 0;
        int numberSum = 0;
        int otherSum = 0;

        Scanner scan = new Scanner(System.in);

        System.out.println("请输入字符串:");

        String str = scan.nextLine();

        char[] ch = str.toCharArray();

        for(int i = 0 ; i < ch.length; i++){
            if(Character.isLetter(ch[i])){
                letterSum++;
            }else if(Character.isSpaceChar(ch[i])){
                blankSum++;
            }else if(Character.isDigit(ch[i])){
                numberSum++;
            }else{
                otherSum++;
            }
        }

        System.out.println("输入的字符串中共有字母:"+letterSum);
        System.out.println("输入的字符串中共有空格:"+blankSum);
        System.out.println("输入的字符串中共有数字:"+numberSum);
        System.out.println("输入的字符串中共有其他字符:"+otherSum);
    }
}

mybatis工作原理

1.首先要建立一个sqlSessionFactory:
建一个工具类,在里面引入核心配置文件,将核心配置文件转化成流文件,利用sqlSessionFactoryBuiler这个类调用build方法将材料(核心配置文件流)实例化一个sqlSessionfactor(sqlSessiongong工厂,用来生产sqls
Session),最后写一个getSqlSession方法

2 创建核心配置文件:
官网里有模板,里面主要包括连接数据库所需要的几个配置(driver,url,username,pwd),和注册机(每个mapper都要在注册机中注册)

3 最后crud操作:调用工具类的getSqlSession方法–>获得sqlSession(相当于connection)利用sqlSession去连接指定mapper接口最后执行sql

jvm内存模型

JVM 内存模型共分为虚拟机栈,堆,方法区,程序计数器,本地方法栈五个部分。

  • Java 虚拟机栈与程序计数器一样,Java 虚拟机栈(Java Virtual MachineStacks)也是线程私有的,它的生命周期与线程相同。
  • Java 堆对于大多数应用来说,Java 堆(Java Heap)是Java 虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。数组既在栈空间分配数组名称, 又在堆空间分配数组实际的大小!
  • 方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,字符串也存储在方法区的字符串常量池中。
  • 程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。
  • 本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。

注意:栈有一个很重要的特殊性,就是存在栈中的数据可以共享假设我们同时定义int a = 3; int b = 3;编译器先处理 int a = 3;首先它会在栈中创建一个变量为 a 的引用,然后查找有没有字面值为 3 的地址,没找到,就开辟一个存放 3 这个字面值的地址,然后将 a 指向 3 的地址。接着处理 int b = 3;在创建完 b 的引用变量后,由于在栈中已经有 3 这个字面值,便将 b 直接指向 3 的地址。这样,就出现了 a 与 b 同时均指向 3 的情况。
特别注意的是,这种字面值的引用与类对象的引用不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量也即刻反映出这个变化。相反,通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完 a 与 b 的值后,再令 a=4;那么,b 不会等于 4,还是等于 3。在编译器内部,遇到 a=4;时,它就会重新搜索栈中是否有 4 的字面值,如果没有,重新开辟地址存放 4 的值;如果已经有了,则直接将 a 指向这个地址。因此 a 值的改变不会影响到 b的值。

索引该怎么创建,什么时候会失效

在这里插入图片描述

在这里插入图片描述
有四种方式来添加数据表的索引
第一种方式:ALTER TABLE tbl_name ADD PRIMARY KEY (column_list): 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。

第二种方法:ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。

第三种方法:ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现多次。

第四种方法:ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):该语句指定了索引为 FULLTEXT ,用于全文索引。

什么时候会失效

1.对于创建的多列索引(复合索引),不是使用的第一部分就不会使用索引

alter table student add index my_index(name, age)   // name左边的列, age 右边的列                                                              

select * from student where name = 'aaa'     // 会用到索引

select * from student where age = 18          //  不会使用索引

2.对于使用 like 查询, 查询如果是 ‘%aaa’ 不会使用索引,而 ‘aaa%’ 会使用到索引。

select * from student where name like 'aaa%' // 会用到索引

select * from student where name like '%aaa'        或者   '_aaa'   //  不会使用索引

3.如果条件中有 or, 有条件没有使用索引,即使其中有条件带索引也不会使用,换言之, 就是要求使用的所有字段,都必须单独使用时能使用索引。

4.如果列类型是字符串,那么一定要在条件中使用引号引用起来,否则不使用索引。

5.如果mysql认为全表扫面要比使用索引快,则不使用索引。

如何避免索引失效

1,复合索引不要跨列或者无序使用(最佳左前缀)复合索引,尽量使用全索引匹配

2,不要在索引上进行任何操作(计算、函数、类型转换),where a.x *3 则失效,复合索引一个失效则其它索引都失效
独立索引,左边失效,右边不失效,不产生影响

3,复合索引不能使用 不等于 != ,is null

4,like尽量以“常量开头”,不要以’%'开头

5,尽量不使用 or ,否则索引失效or 左右索引都失效

Redis实现乐观锁

悲观锁:
很悲观,认为什么时候都会出问题,无论做什么都会加锁
乐观锁:
很乐观,认为在什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人去改过数据。
获取version。
更新的时候比较verison
wach是加锁的意思

127.0.0.1:6379> set k1 100
OK
127.0.0.1:6379> set k2 0
OK
127.0.0.1:6379> watch k1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby k1 20
QUEUED
127.0.0.1:6379> incrby k2 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20

这个是加锁之后正常执行流程
异常流程:
在这里插入图片描述
执行事务的时候,另外一个线程修改了值,这个时候,就会导致nil(),导致事务进行失败
需要unwatch解除锁,重新绑定:

127.0.0.1:6379> unwatch
OK
127.0.0.1:6379> watch k1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby k1 20
QUEUED
127.0.0.1:6379> incrby k2 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 60
2) (integer) 20

栈的出栈和入栈规律

规律如下:
已知栈的输入序列是1,2,3,…,n,输出序列是a1,a2,…ai,…,an。
然后我们任选一个数ai,并筛选ai到an之间所有<=ai的元素,则它们一定是按照从大到小的顺序排列的。

(“从大到小“不一定紧紧相邻,只代表相对位置关系,比如(…,10,…,7,…,3,…,1,…)
举例:
入栈顺序:1 2 3 4 5 【n=5】
出栈顺序:3 2 1 5 4
验证:
让i=1,那么ai=3,后面小于3的有2,1。刚好3,2,1是按照从大到小的顺序排列的
让i=2,那么ai=2,后面小于2的有1。刚好2,1是按照从大到小的顺序排列的
让i=3,那么ai=1,后面小于1的有NULL,满足。
让i=4,那么ai=5,后面小于5的有4。刚好5,4是按照从大到小的顺序排列的
让i=5,那么ai=4,后面小于4的有NULL,满足。

对HashMap进行排序

已知一个 HashMap<Integer,User>集合, User 有 name和 age属性。请写一个方法实现对HashMap 的排序功能,该方法接收 HashMap<Integer,User>为形参,返回类型为HashMap<Integer,User>,
要求对 HashMap 中的 User 的 age 倒序进行排序。排序时 key=value 键值对不得拆散。

注意:要做出这道题必须对集合的体系结构熟悉。HashMap 本身就是不可排序的,但是该道题偏偏让给HashMap 排序,那我们就得想在 API 中有没有这样的 Map 结构是有序的。LinkedHashMap,对的,就是他,他是Map 结构,也是链表结构,有序的,更可喜的是他是 HashMap 的子类,我们返回 LinkedHashMap<Integer,User>即可,还符合面向接口(父类编程的思想)。

 public class HashMapTest {
2. public static void main(String[] args) {
3. HashMap<Integer, User> users = new HashMap<>();
4. users.put(1, new User("张三", 25));
5. users.put(3, new User("李四", 22));
6. users.put(2, new User("王五", 28));
7. System.out.println(users);
8. HashMap<Integer,User> sortHashMap = sortHashMap(users);
9. System.out.println(sortHashMap);
10. /**
11. * 控制台输出内容
12. * {1=User [name=张三, age=25], 2=User [name=王五, age=28], 3=User [name=李四, age=22]}
13. {2=User [name=王五, age=28], 1=User [name=张三, age=25], 3=User [name=李四, age=22]}
14. */
15. }
16.
16. public static HashMap<Integer, User> sortHashMap(HashMap<Integer, User> map) {
17. // 首先拿到 map 的键值对集合
18. Set<Entry<Integer, User>> entrySet = map.entrySet();
20.
19. // 将 set 集合转为 List 集合,为什么,为了使用工具类的排序方法
20. List<Entry<Integer, User>> list = new ArrayList<Entry<Integer, User>>(entrySet);
21. // 使用 Collections 集合工具类对 list 进行排序,排序规则使用匿名内部类来实现
22. Collections.sort(list, new Comparator<Entry<Integer, User>>()
{ 25.
23. @Override
24. public int compare(Entry<Integer, User> o1, Entry<Integer, User> o2) {
25. //按照要求根据 User 的 age 的倒序进行排
26. return o2.getValue().getAge()-o1.getValue().getAge();
27. }
28. });
29. //创建一个新的有序的 HashMap 子类的集合
30. LinkedHashMap<Integer, User> linkedHashMap = new LinkedHashMap<Integer, User>();
31. //将 List 中的数据存储在 LinkedHashMap 中
32. for(Entry<Integer, User> entry : list){
33. linkedHashMap.put(entry.getKey(), entry.getValue());
34. }
35. //返回结果
39. return linkedHashMap;
40. }
41. }

ArrayList和LinkedList的区别

1.对 ArrayList 和 LinkedList 而言,在列表末尾增加一个元素所花的开销都是固定的。对 ArrayList 而言,主要是在内部数组中增加一项,指向所添加的元素,偶 尔可能会导致对数组重新进行分配;而对 LinkedList 而言,这个开销是统一的,分配一个内部 Entry 对象。
2.在 ArrayList 的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在 LinkedList 的中间插入或删除一个元素的开销是固定的。
3.LinkedList 不支持高效的随机元素访问。
4.ArrayList 的空间浪费主要体现在在 list 列表的结尾预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗相当的空间可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList 会提供比较好的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元
素时,就应该使用 LinkedList 了。

对线程池的理解

如果问到了这样的问题,可以展开的说一下线程池如何用、线程池的好处、线程池的启动策略

第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定
性,使用线程池可以进行统一的分配,调优和监控。

动静态代理的区别,什么场景使用?

1.静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
2.静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。
3.动态代理是实现 JDK 里的 InvocationHandler 接口的 invoke 方法,但注意的是代理的是接口,也就是你的
4.业务类必须要实现接口,通过 Proxy 里的 newProxyInstance 得到代理对象。
5.还有一种动态代理 CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态修改字节码达到修改类的目的。
6.AOP 编程就是基于动态代理实现的,比如著名的 Spring 框架、Hibernate 框架等等都是动态代理的使用例子。

Java 中引用类型都有哪些?(重要)

Java 中对象的引用分为四种级别,这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

Java 中为什么会有 GC 机制呢

安全性考虑;
减少内存泄露;
减少程序员工作量。

对于 Java 的 GC 哪些内存需要回收

内存运行时 JVM 会有一个运行时数据区来管理内存。它主要包括 5 大部分:程序计数器(Program CounterRegister)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(MethodArea)、堆(Heap).而其中程序计数器、虚拟机栈、本地方法栈是每个线程私有的内存空间,随线程而生,随线程而亡。例如栈中每一个栈帧中分配多少内存基本上在类结构确定是哪个时就已知了,因此这 3 个区域的内存分配和回收都是确定的,无需考虑内存回收的问题。

但方法区和堆就不同了,一个接口的多个实现类需要的内存可能不一样,我们只有在程序运行期间才会知道会创建哪些对象,这部分内存的分配和回收都是动态的,GC 主要关注的是这部分内存。

总而言之,GC 主要进行回收的内存是 JVM 中的方法区和堆;

既然有 GC 机制,为什么还会有内存泄露的情况

理论上 Java 因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是 Java 被广泛使用于服务器端编程的一个重要原因)。然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被 GC 回收,因此也会导致内存泄露的发生。

例如 hibernate 的 Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。

在开发中遇到过内存溢出么?原因有哪些?解决方法有哪些?

引起内存溢出的原因有很多种,常见的有以下几种:

  • 1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
  • 2.集合类中有对对象的引用,使用完后未清空,使得 JVM 不能回收;
  • 3.代码中存在死循环或循环产生过多重复的对象实体;
  • 4.使用的第三方软件中的 BUG;
  • 5.启动参数内存值设定的过小;

内存溢出的解决方案:

  • 第一步,修改 JVM 启动参数,直接增加内存。(-Xms,-Xmx 参数一定不要忘记加。)
  • 第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。
  • 第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。
  • 第四步,使用内存查看工具动态查看内存使用情况。

http 的长连接和短连接

HTTP 协议有 HTTP/1.0 版本和 HTTP/1.1 版本。HTTP1.1 默认保持长连接(HTTP persistent connection,也翻译为持久连接),数据传输完成了保持 TCP 连接不断开(不发 RST 包、不四次握手),等待在同域名下继续用这个
通道传输数据;相反的就是短连接。

在 HTTP/1.0 中,默认使用的是短连接。也就是说,浏览器和服务器每进行一次 HTTP 操作,就建立一次连接,任务结束就中断连接。从 HTTP/1.1 起,默认使用的是长连接,用以保持连接特性。

http 常见的状态码

200 OK //客户端请求成功

301 Moved Permanently(永久移除),请求的 URL 已移走。Response 中应该包含一个 Location URL, 说明资源现在所处的位置

302 found 重定向

400 Bad Request //客户端请求有语法错误,不能被服务器所理解

401 Unauthorized //请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用

403 Forbidden //服务器收到请求,但是拒绝提供服务

404 Not Found //请求资源不存在,eg:输入了错误的 URL

在单点登录中,如果 cookie 被禁用了怎么办?

单点登录的原理是后端生成一个 session ID,然后设置到 cookie,后面的所有请求浏览器都会带上 cookie,然后服务端从 cookie 里获取 session ID,再查询到用户信息。所以,保持登录的关键不是 cookie,而是通过cookie 保存和传输的 session ID,其本质是能获取用户信息的数据。除了 cookie,还通常使用 HTTP 请求头来传输。但是这个请求头浏览器不会像 cookie 一样自动携带,需要手工处理。

XML 技术

xml 是一种可扩展性标记语言,支持自定义标签(使用前必须预定义)使用 DTD 和 XML Schema 标准化 XML 结构。

优点:用于配置文件,格式统一,符合标准;用于在互不兼容的系统间交互数据,共享数据方便;
缺点:xml 文件格式复杂,数据传输占流量,服务端和客户端解析 xml 文件占用大量资源且不易维护;

Xml 常用解析器有 2 种,分别是:DOM 和 SAX;
主要区别在于它们解析 xml 文档的方式不同。使用 DOM 解析,xml 文档以 DOM树形结构加载入内存,而 SAX 采用的是事件模型,

Linux 命令

列出文件列表:ls 【参数 -a -l】
创建目录和移除目录:mkdir rmdir
用于显示文件后几行内容:tail
打包:tar -xvf
打包并压缩:tar -zcvf
查找字符串:grep
显示当前所在目录:pwd
创建空文件:touch
编辑器:vim vi
动态打印日志信息:tail –f 日志文件

通常用 ps 查看进程 PID ,用 kill 命令终止进程。
ps 命令用于查看当前正在运行的进程。
grep 是搜索
例如: ps -ef | grep java
表示查看所有进程里 CMD 是 java 的进程信息。
ps -aux | grep java
-aux 显示所有状态
kill 命令用于终止进程。
例如: kill -9 [PID]
-9 表示强迫进程立即停止。

Mysql 性能优化

1、当只要一行数据时使用 limit 1
查询时如果已知会得到一条数据,这种情况下加上 limit 1 会增加性能。因为 mysql 数据库引擎会在找到一条结果停止搜索,而不是继续查询下一条是否符合标准直到所有记录查询完毕。

2、选择正确的数据库引擎
Mysql 中有两个引擎 MyISAM 和 InnoDB,每个引擎有利有弊。

MyISAM 适用于一些大量查询的应用,但对于有大量写功能的应用不是很好。甚至你只需要update 一个字段整个表都会被锁起来。而别的进程就算是读操作也不行要等到当前 update 操作完成之后才能继续进行。另外,MyISAM 对于 select count(*)这类操作是超级快的。

InnoDB 的趋势会是一个非常复杂的存储引擎,对于一些小的应用会比MyISAM 还慢,但是支持“行锁”,所以在写操作比较多的时候会比较优秀。并且,它支持很多的高级应用,例如:事物。

3. 用 not exists 代替 not in
Not exists 用到了连接能够发挥已经建立好的索引的作用,not in 不能使用索引。Not in 是最慢的方式要同每条记录比较,在数据量比较大的操作红不建议使用这种方式。

4. 对操作符的优化,尽量不采用不利于索引的操作符
如:in not in is null is not null <> 等

某个字段总要拿来搜索,为其建立索引:
Mysql 中可以利用 alter table 语句来为表中的字段添加索引,语法为:alter table 表明add index (字段名);

Mysql 中四种隔离级别分别是什么?

在这里插入图片描述
读未提交(READ UNCOMMITTED):未提交读隔离级别也叫读脏,就是事务可以读取其它事务未提交的数据。
读已提交(READ COMMITTED):在其它数据库系统比如 SQL Server 默认的隔离级别就是提交读,已提交读隔离级别就是在事务未提交之前所做的修改其它事务是不可见的。
可重复读(REPEATABLE READ):保证同一个事务中的多次相同的查询的结果是一致的,比如一个事务一开始查询了一条记录然后过了几秒钟又执行了相同的查询,保证两次查询的结果是相同的,可重复读也是 mysql 的默认隔离级别。
可串行化(SERIALIZABLE):可串行化就是保证读取的范围内没有新的数据插入,比如事务第一次查询得到某个范围的数据,第二次查询也同样得到了相同范围的数据,中间没有新的数据插入到该范围中。

在千万级的数据库查询中,如何提高效率?

  • 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
  • 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查
    询 : select id from t where num=0
  • 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过 6 个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
  • 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
  • 应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描
  • in 和 not in 也要慎用,否则会导致全表扫描,如: select id from t where num in(1,2,3) 对于连续的数值,能用 between 就不要用 in 了: select id from t where num between 1 and 3
  • 应尽量避免在where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。

Mybatis 中#和$的区别

#相当于对数据 加上 双引号,KaTeX parse error: Expected 'EOF', got '#' at position 25: …,为了防止sql注入,一般能用#̲的就别用

Redis 的持久化

RDB 持久化:该机制可以在指定的时间间隔内生成数据集的时间点快照

AOF 持久化:记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。 Redis 还可以在后台对 AOF 文件进行重写(rewrite),使得 AOF 文件的体积不会超出保存数据集状态所需的实际大小

无持久化:让数据只在服务器运行时存在。

同时应用 AOF 和 RDB:当 Redis 重启时, 它会优先使用 AOF 文件来还原数据集, 因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。

RDB 的优缺点:

优点:RDB 是一个非常紧凑(compact)的文件,它保存了 Redis 在某个时间点上的数据集。 这种文件非常适合用于进行备份: 比如说,你可以在最近的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心,或者亚马逊 S3 中。RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork出一个子进程,然后这个子进程就会处理接下来的所有保存作,父进程无须执行任何磁盘 I/O 操作。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

缺点:如果你需要尽量避免在服务器故障时丢失数据,那么 RDB 不适合你。 虽然 Redis 允许你设置不同的保存点(save point)来控制保存 RDB 文件的频率, 但是, 因为 RDB 文件需要保存整个数据集的状态, 所以它并不是一个轻松的操作。 因此你可能会至少 5 分钟才保存一次 RDB 文件。 在这种情况下, 一旦发生故障停机, 你就可能会丢失好几分钟的数据。每次保存 RDB 的时候,Redis 都要 fork() 出一个子进程,并由子进程来进行实际的持久化工作。 在数据集比较庞大时, fork() 可能会非常耗时,造成服务器在某某毫秒内停止处理客户端;如果数据集非常巨大,并且 CPU 时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒。

AOF 的优缺点:

优点1:使用 AOF 持久化会让 Redis 变得非常耐久(much more durable)你可以设置不同的 fsync 策略,比如无 fsync ,每秒钟一次 fsync ,或者每次执行写入命令时 fsync 。 AOF 的默认策略为每秒钟 fsync 一次,在这种配下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync 会在后台线程执行,所以主线程可以继续努力地处理命令请求)。AOF 文件是一个只进行追加操作的日志文件(append onlylog), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等),redis-check-aof 工具也可以轻易地修复这种问题。

优点2:Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。

缺点:对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。

下列那一个选项按照顺序包括了 OSI 模型的 7 个层次

物理层 数据链路层 网络层 传输层 会话层 表示层 应用层

计算完数

public class wsTest {
	public static void main(String[] args) {
		for(int m=2;m<1000;m++){
			int s=0;
			for(int i=1;i<m;i++){
				if((m%i)==0)
					s+=i;
			}
		if(s==m){
		System.out.print(m+" its factors are:");
		for(int j=1;j<m;j++)
	{
	if((m%j)==0){
	System.out.print(j);
	System.out.print(" ");
}
}
	System.out.println();
}
}
}
}
//结果:
//6 its factors are:1 2 3
//28 its factors are:1 2 4 7 14
//496 its factors are:1 2 4 8 16 31 62 124 248

Java 中的值传递和引用传递

值传递:
方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。

引用传递:
也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象。

常用排序算法复杂度

在这里插入图片描述

常见的 5 个 linux 系统日志

access-log: 纪录 HTTP/web 的传输
acct/pacct: 纪录用户命令
aculog: 纪录 MODEM 的活动
btmp: 纪录失败的纪录
lastlog: 纪录最近几次成功登录的事件和最后一次不成功的登录

相对于 JDK1.4,JDK1.5 有哪些新特性?

泛型(Generics)
增强的“for”循环(Enhanced For loop)
自动装箱/ 自动拆箱(Autoboxing/unboxing)
类型安全的枚举(Type safe enums)
静态导入(Static import)
可变参数(Var args)

什么叫脏数据,什么叫脏读

脏数据在临时更新(脏读)中产生。事务 A 更新了某个数据项 X,但是由于某种原因,事务 A 出现了问题,于是要把 A 回滚。但是在回滚之前,另一个事务 B 读取了数据项 X 的值(A 更新后),A 回滚了事务,数据项恢复了原值。事务 B 读取的就是数据项 X 的就是一个“临时”的值,就是脏数据。

脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。

requestbody和responsebody的区别

@RequestBody的作用是将前端传来的json格式的数据转为自己定义好的javabean对象
@ResponseBody的作用是将后端以return返回的javabean类型数据转为json类型数据
在这里插入图片描述

如果前端传到后端的参数名不一样怎么办

在这里插入图片描述

提交任务时线程池已满,会发生什么?

这里区分一下:

1、如果使用的是无界队列 LinkedBlockingQueue,也就是无界队列的话,没关系,继续添加任务到阻塞队列中等待执行,因为 LinkedBlockingQueue 可以近乎认为是一个无穷大的队列,可以无限存放任务
2、如果使用的是有界队列比如 ArrayBlockingQueue,任务首先会被添加到ArrayBlockingQueue 中,ArrayBlockingQueue 满了,会根据maximumPoolSize 的值增加线程数量,如果增加了线程数量还是处理不过来,ArrayBlockingQueue 继续满,那么则会使用拒绝策略RejectedExecutionHandler 处理满了的任务,默认是 AbortPolicy

static关键字的作用

有四种使用情况:成员变量、成员方法、代码块和内部类

  • static成员变量:java中可以通过statin关键字修饰变量达到全局变量的效果。static修饰的变量(静态变量)属于类,在类第一次通过类加载器到jvm时被分配内存空间
  • static成员方法:static修饰的方法属于类方法,不需要创建对象就可以调用。static方法中不能使用this和super等关键字,不能调用非static方法,只能访问所属类的静态成员变量和静态方法
  • static 代码块:JVM在加载类时会执行static代码块,static代码块常用于初始化静态变量,static代码只会在类被加载时执行且执行一次
  • static内部类:static内部类可以不依赖外部类实例对象而被实例化,而内部类需要在外部类实例化后才能被实例化。静态内部类不能访问外部类的普通变量,只能访问外部类的静态成员变量和静态方法

java基本数据类型的默认值

int类型定义的数组,初始化默认是0

String类型定义的数组,默认值是null

char类型定义的数组,默认值是0对应的字符

double类型定义的数组,默认值是0.0

float类型定义的数组,默认值是0.0

而且不仅仅是数组第一个元素有默认值,所有的数组的默认值和上面的规则一样

boolean false

char ‘/uoooo’(null)

byte (byte)0

short (short)0

int 0

long 0L

float 0.0f

double 0.0d

在这里插入图片描述

索引使用原则

1、表的主键、外键必须有索引;

2、数据量超过300的表应该有索引;

3、经常与其他表进行连接的表,在连接字段上应该建立索引;

4、经常出现在Where子句中的字段,特别是大表的字段,应该建立索引;

5、索引应该建在选择性高的字段上;

6、索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引;

7、复合索引的建立需要进行仔细分析;尽量考虑用单字段索引代替:

8、频繁进行数据操作的表,不要建立太多的索引;

9、删除无用的索引,避免对执行计划造成负面影响;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值