面试题笔记
JVM
JVM的工作原理
1 | JVM是JRE的一部分,Java语言最重要的特点就是跨平台运行。使用JVM就是为了支持与操作系统无关,实现跨平台。(怎么跨平台的:jvm它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统) |
一、JVM内存分为堆、方法区、虚拟机栈、本地方法栈、程序计数器五个部分。
二、堆和方法区是线程共享的,虚拟机栈、本地方法栈和程序计数器是线程隔离的。
三、1.堆主要是存放对象实例的也包括数组,是垃圾管理的主要作用区。
JVM的生命周期
(1)JVM实例的诞生:当启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void main(String[] args)函数的class都可以作为JVM实例运行的起点。
(2)JVM实例的运行 main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以标明自己创建的线程是守护线程。
(3)JVM实例的消亡:当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出。
堆与栈
栈是运行时的单位,而堆是存储的单位。
栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么放、放在哪儿。
在Java中一个线程就会相应有一个线程栈与之对应,这点很容易理解,因为不同的线程执行逻辑有所不同因此需要一个独立的线程栈。而堆则是所有线程共享的。栈因为是运行单位,因此里面存储的信息都是跟当线程(或程序)相关信息的。包括局部变量、程序运行状态、方法返回值等等;而堆只负责存储对象信息。
堆中存的是对象。栈中存的是基本数据类型和堆中对象的引用。
堆和栈中,栈是程序运行最根本的东西。程序运行可以没有堆,但是不能没有栈。
Java 的类加载过程
一般来说,我们把 Java 的类加载过程分为三个主要步骤:加载,连接,初始化,具体行为在 Java 虚拟机规范里有非常详细的定义。
首先是加载过程(Loading),它是 Java 将字节码数据从不同的数据源读取到 JVM 中,并映射为 JVM 认可的数据结构(Class 对象),这里的数据源可能是各种各样的形态,比如 jar 文件,class 文件,甚至是网络数据源等;如果输入数据不是 ClassFile 的结构,则会抛出 ClassFormatError。加载阶段是用户参与的阶段,我们可以自定义类加载器,去实现自己的类加载过程。
第二阶段是连接(Linking),这是核心的步骤,简单说是把原始的类定义信息平滑地转入 JVM 运行的过程中。这里可进一步细分成三个步骤:1,验证(Verification),这是虚拟机安全的重要保障,JVM 需要核验字节信息是符合 Java 虚拟机规范的,否则就被认为是 VerifyError,这样就防止了恶意信息或者不合规信息危害 JVM 的运行,验证阶段有可能触发更多 class 的加载。2,准备(Pereparation),创建类或者接口中的静态变量,并初始化静态变量的初始值。但这里的“初始化”和下面的显示初始化阶段是有区别的,侧重点在于分配所需要的内存空间,不会去执行更进一步的 JVM 指令。3,解析(Resolution),在这一步会将常量池中的符号引用(symbolic reference)替换为直接引用。在 Java 虚拟机规范中,详细介绍了类,接口,方法和字段等各方面的解析。
最后是初始化阶段(initialization),这一步真正去执行类初始化的代码逻辑,包括静态字段赋值的动作,以及执行类定义中的静态初始化块内的逻辑,编译器在编译阶段就会把这部分逻辑整理好,父类型的初始化逻辑优先于当前类型的逻辑。再来谈谈双亲委派模型,简单说就是当加载器(Class-Loader)试图加载某个类型的时候,除非父类加载器找不到相应类型,否则尽量将这个任务代理给当前加载器的父加载器去做。使用委派模型的目的是避免重复加载 Java 类型。
JVM常用垃圾算法?
==和equals
equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。
== 的作用:
基本类型:比较的就是值是否相同
引用类型:比较的就是地址值是否相同
equals 的作用:
引用类型:默认情况下,比较的是地址值。
注:不过,我们可以根据情况自己重写该方法。一般重写都是自动生成,比较对象的成员变量值是否相同
重写equals方法时,需要遵循哪些约定?
散列表
①哈希表是基于数组的一种存储方式.它主要由哈希函数和数组构成。当要存储一个数据的时候,首先用一个函数计算数据的地址,然后再将数据存进指定地址位置的数组里面。这个函数就是哈希函数,而这个数组就是哈希表。
②哈希冲突是指哈希函数算出来的地址被别的元素占用了,也就是,这个位置有人了。好的哈希函数会尽量避免哈希冲突。
1.什么是散列表?
依据关键码值(key)直接获取表中对应纪录的一种数据结构。
其中,将关键码值映射到表中的位置的函数叫散列函数(hash函数),
存放记录的数组称之为散列表。
2.散列表的工作原理:
首先我们使用散列函数将给定键转化为一个“数组的索引”,(key如果相同就是碰撞)
得到了索引后,我们就可以像访问数组一样,通过这个索引访问到相应的键值对。
3.散列表常见的一些实现类。
Hashtable: 线程安全,但是性能低,不建议使用。
HashMap:线程不安全,性能高。
注:
可以调用Collections.synchronizedMap来将hashMap
转换成一个线程安全的map。
ConcurrentHashMap: 线程安全,并且性能良好。
解决哈希冲突的办法
事务
(1)什么是事务?
事务(Transaction):是数据库领域中,一种能保证多项增删改操作能够全部执行成功,或全部执行失败的机制!
(2)事务的特点(ACID)
A.原子性(atomicity):
事务所涉及的各个操作要么全部成功,要么全部失败。
C.一致性(consistency):
事务完成之后,不允许非法的数据保存到数据库。一个事务在执行之前和执行之后,数据的完整性都必须处于一致性状态。
I.隔离性(isolation):
多个事务可以同时执行,彼此不所影响。
事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
D.持久性(durability):
事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
业务层
什么是业务:业务(Service),对于普通用户来说,就是一个“功能”,但是,它可能是由多项数据操作组成的,例如“用户注册”就是一个业务,它至少由“根据用户名查询数据”和“插入数据”组成,在编写代码时,业务层主要完成业务流程和业务逻辑的控制,业务流程指的是先做什么、后做什么,业务逻辑指的是什么情况下能做什么、不能做什么,最终,业务层的目标是保障数据的完整性、安全性。
POJO
POJO是各种实体类的统称,常用的实体类包括DO/DTO/BO/VO。
- DO:与数据库表相对应的实体类,属性与表中字段相对应
- DTO:业务层传输数据时使用的实体类
- BO:业务层对外提供远程调用时使用的实体类
- VO:供视图层使用的实体类
Spring
什么是Spring:
简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
Spring框架的好处,为什么要用Spring?
1.方便解耦,便于开发(Spring就是一个大工厂,可以将所有对象的创建和依赖关系维护都交给spring管理)
2.spring支持aop编程(spring提供面向切面编程,可以很方便的实现对程序进行权限拦截和运行监控等功能)
3.声明式事务的支持(通过配置就完成对事务的支持,不需要手动编程)
4.方便程序的测试,spring 对junit4支持,可以通过注解方便的测试spring 程序
5.方便集成各种优秀的框架()
6.降低javaEE API的使用难度(Spring 对javaEE开发中非常难用的一些API 例如JDBC,javaMail,远程调用等,都提供了封装,是这些API应用难度大大降低)
AOP
什么是AOP:
简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低 模块间的耦合度,并有利于未来的可操作性和可维护性。
核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横 切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。
Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
Spring bean的作用域*
Spring默认是单例的,当一个bean的作用域为singleton时,那么Spring容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义的相匹配,则只会返回bean的同一实例。
prototype作用域的bean会导致在每次对该bean请求时都会创建一个新的bean实例。
bean的注入属性有几种方式
- 构造器注入
- set注入
- 接口注入
单例模式
1 | public class King { |
以上是饿汉式单例模式
1 | public class King { |
以上,就是完整的懒汉式的单例模式!
小结:单例模式的特点就是“单一实例”,表现为“同一时间内,某个类的对象只有1个”!单例模式分为“饿汉式”和“懒汉式”这2种,前者是“早早的创建出对象,随时可以获取”,后者是“不到逼不得已不会创建对象”!
自动装配
byName
:要求被装配的属性名称,与被Spring管理的对象的名称(调用getBean()
方法给出的参数名)必须相同;
byType
:要求被装配的属性的类型,在Spring容器中存在匹配类型的对象,当应用这种机制时,必须在Spring容器中保证匹配类型的对象只有1个,否则,将会出现NoUniqueBeanDefinitionException
异常;
Spring 事务的传播属性
所谓spring事务的传播属性,就是定义在存在多个事务同时存在的时候,spring应该如何处理这些事务的行为。这些属性在TransactionDefinition中定义,具体常量的解释见下表:
常量名称 | 常量解释 |
---|---|
PROPAGATION_REQUIRED | 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring 默认的事务的传播。 |
REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务,外层事务失败回滚之后,不能回滚内层事务执行的结果,内层事务失败抛出异常,外层事务捕获,也可以不处理回滚操作 |
supports | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
mandatory | 支持当前事务,如果当前没有事务,就抛出异常。 |
not_supported | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
never | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
nested | 如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。 |
Spring中的隔离级别
常量 | 解释 |
---|---|
ISOLATION_DEFAULT | 这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与 JDBC 的隔离级别相对应。 |
ISOLATION_READ_UNCOMMITTED | 这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。 |
ISOLATION_READ_COMMITTED | 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。 |
ISOLATION_REPEATABLE_READ | 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。 |
ISOLATION_SERIALIZABLE | 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。 |
Spring MVC
SpringMVC框架的作用
SpringMVC框架主要解决了接收请求与处理响应的问题,也可以认为是解决了V-C交互的问题,与M其实没有关系。
在传统的Java EE的开发模式下,可能存在Servlet
组件数量太多的问题,会导致项目的管理难度太大,且运行时,会有大量的Servlet
对象长期占用内存的问题!
另外,传统的Java EE开发模式下,数据的处理过程中代码量相对较大,而SpringMVC非常大极度的简化了开发量!
SpringMVC的流程
发送请求-接收请求-记录请求与控制器的对应关系-委托请求到控制器-处理后得到的数据及视图名称-根据视图名称确定具体的视图组件-产生响应
SpringMVC能否从请求url中截取参数?
可以利用@PathVariable实现。在Controller方法上添加的@RequestMapping
注解中,使用{变量名}
的方式,将url中指定位置的值作为变量。在对应方法的参数中,声明一个接收该变量值的参数,前面使用@PathVariable("变量名")
标注。
SpringMVC框架的核心组件
-DispatcherServlet
:前端控制器,用于接收所有请求,并组织分发;
-HandlerMapping
:记录请求路径与控制器的对应关系;
-Controller
:自定义的处理请求的控制器组件;
-ModelAndView
:控制器组件处理完请求之后得到的结果,包含数据与视图名称;
-ViewResolver
:视图解析器,可以根据视图名称,确定具体的视图组件。
1. 关于@RequestMapping注解
在处理请求的方法之前添加@RequestMapping
注解,可以配置请求路径与处理请求的方法的映射关系!
SpringMVC怎么使用中文?
1 |
|
重写getServletFilters方法,返回CharacterEncodingFilter类,设置字符编码为uft-8,或在web.xml中配置CharacterEncodingFilter过滤器,设置字符编码为utf-8。
转发与重定向的区别
能否共享request对象?
转发可以,而重定向不行。
注:
因为request和response这两个对象的生存时间是在一次请求与响应
期间存在。
转发是服务器内部的行为,具体表现为“控制器将请求转发给视图组件(可以有数据,也可以没有数据)”,对于客户端来说,只发出过1次请求,并且,只知道这1次请求的路径,在客户端的浏览器中,地址栏显示的URL也不会发生变化!同时,由于这是服务器内部的行为,所以,控制器可以向视图组件传递任意数据!从编写代码的角度来看,转发时,需要指定的是视图名称!
MySql
什么是索引
索引是数据库中提高查询效率的技术,数据量越大索引效果越明显,索引类似于目录
索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址,在数据十分庞大的时候,索引可以大大加快查询的速度,
为什么使用索引:
1 | 数据会零散的保存在磁盘中的每个磁盘块中,如果不使用索引,查找数据只能挨个遍历每一个磁盘块进行查找,如果使用了索引后,磁盘块会以树桩结构进行保存,查找数据时大大降低了磁盘块的访问量,从而达到了提高查询效率的目的 |
mysql 索引是怎么实现的?
具体来说 MySQL 中的索引,不同的数据引擎实现有所不同,但目前主流的数据库引擎的索引都是 B+ 树实现的,B+ 树的搜索效率,
可以到达二分法的性能,找到数据区域之后就找到了完整的数据结构了,所有索引的性能也是更好的。
什么是Serializable接口
一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才能被序列化。
什么是序列化?
序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。
为什么要序列化对象
把对象转换为字节序列的过程称为对象的序列化
把字节序列恢复为对象的过程称为对象的反序列化
什么情况下需要序列化?
当我们需要把对象的状态信息通过网络进行传输,或者需要将对象的状态信息持久化,以便将来使用时都需要把对象进行序列化
关于Session
因为HTTP协议是无状态协议,所以,同一个客户端的多次请求,服务器是无法区分这是来自同一个客户端的,如果需要保存用户的某些数据或状态,就需要使用Session。
Cookie和Session
为什么使用Cookie和Session?
浏览器和服务器之间数据传输遵循的是HTTP数据传输协议,此协议属于无状态协议(一次请求对应一次响应,服务器无法跟踪客户端的请求),通过Cookie服务器可以给客户端设置一个标识,设置完之后客户端之后的请求都会带着这个标识,从而识别客户端. 但是Cookie由于是明文保存在客户端的数据,可以被客户端伪造造成安全隐患, 这时Session的产生解决了此问题,Session基于Cookie实现,但是数据保存在了服务器端,这样保存的数据就不能被伪造从而提高了安全性
作用: Cookie和Session都是为了实现多个Servlet之间共享数据而存在的
Cookie:数据保存在客户端,类似于打孔式的会员卡,
- 保存时间: 默认保存在内存中浏览器关闭时就会被删除,如果设置了保存时间,数据会保存到磁盘中,时间到了后再销毁
- 保存数据大小: cookie保存的数据不能超过4k
- 只能保存字符串数据
- 应用场景: 长时间保存的数据
Session:数据保存在服务器,类似于银行卡
- Session保存时间为半个小时, 这个时间可以修改但不建议,因为Session对象保存在服务器中会占用资源,Session不建议数据存储时间太久,而且Session的工作原理基于Cookie,在Cookie中保存了sessionId,并且是在内存中保存,浏览器关闭时sessionId就删除.
- 保存数据大小:没有限制
- 可以保存任意对象
- 应用场景: 记录登录状态
4. 拦截器(Interceptor)
拦截器:是一种可以使得若干种请求都会自动的执行其中的代码组件!该组件对所处理的请求可以选择放行,或选择阻止继续执行!
在SpringMVC项目中,如果需要使用拦截器,首先,需要自定义类,实现HandlerInterceptor
拦截器接口:
附1:关于拦截器(Interceptor)和过滤器(Filter)
过滤器(Filter)是Java EE中的组件,而拦截器(Interceptor)是SpringMVC中的组件!
过滤器(Filter)是执行在所有的Servlet
之前的组件,而SpringMVC中的拦截器的第1次执行是在DispatcherServlet
之后,且在Controller
之前执行的!(对应SpringMVC核心执行流程图,过滤器是1号位置执行,而拦截器第1次执行是在4号位置)
MyBatis框架的作用
MyBatis框架最直接的作用就是简化持久层开发!
持久层:处理数据持久化的组件;
持久化:将数据永久的存储下来;
集合
Set 无序,唯一
HashSet如何保证元素的唯一性
依赖两个方法:hashCode()和equals()
TreeSet底层数据结构是红黑树
如何保证元素排序的呢?
自然排序、比较器排序
如何保证元素唯一性的呢?
根据比较的返回值是否是0来决定
List 有序,可重复
ArrayList和Vector底层数据结构是数组
linkedList底层数据结构是链表
只有Vector是线程安全的
Map
- TreeMap是有序的,HashMap和HashTable是无序的。
- Hashtable的方法是同步的,HashMap的方法不是同步的。这是两者最主要的区别。
- Hashtable是线程安全的,HashMap不是线程安全的。
TreeMap底层实现是红黑树
TreeSet和TreeMap的区别
其中 TreeMap 是 Map 接口的常用实现类,而 TreeSet 是 Set 接口的常用实现类。虽然 TreeMap 和TreeSet 实现的接口规范不同,但 TreeSet 底层是通过 TreeMap 来实现的(如同HashSet底层是是通过HashMap来实现的一样),因此二者的实现方式完全一样。而 TreeMap 的实现就是红黑树算法。
相同点:
- TreeMap和TreeSet都是非同步集合,因此他们不能在多线程之间共享,不过可以使用方法Collections.synchroinzedMap()来实现同步
- 运行速度都要比Hash集合慢,他们内部对元素的操作时间复杂度为O(logN),而HashMap/HashSet则为O(1)。
- TreeMap和TreeSet都是有序的集合,也就是说他们存储的值都是拍好序的。
不同点:
- 最主要的区别就是TreeSet和TreeMap分别实现Set和Map接口
- TreeSet只存储一个对象,而TreeMap存储两个对象Key和Value(仅仅key对象有序)
- TreeSet中不能有重复对象,而TreeMap中可以存在
- TreeMap的底层采用红黑树的实现,完成数据有序的插入,排序。
红黑树的特点:
- 性质 1:每个节点要么是红色,要么是黑色。
- 性质 2:根节点永远是黑色的。
- 性质 3:所有的叶节点都是空节点(即 null),并且是黑色的。
- 性质 4:每个红色节点的两个子节点都是黑色。(从每个叶子到根的路径上不会有两个连续的红色节点)
- 性质 5:从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点。
集合树状图
数组和集合有什么区别
- 数组声明了它容纳的元素的类型,而集合不声明。
- 数组是静态的,一个数组实例具有固定的大小,一旦创建了就无法改变容量了。而集合是可以动态扩展容量,可以根据需要动态改变大小,集合提供更多的成员方法,能满足更多的需求。
- 数组的存放的类型只能是一种(基本类型/引用类型),集合存放的类型可以不是一种(不加泛型时添加的类型是Object)。
- 数组是java语言中内置的数据类型,是线性排列的,执行效率或者类型检查都是最快的。
数组 | 集合 |
---|---|
静态的 ,有固定的大小 | 动态的,大小不固定 |
存放类型只能是一种 | 存放类型不只是一种 |
线性排列,速度快 | 多种排列方式,速度不一 |
String
StringBuffer和StringBuilder的区别
在改变字符串时,都不会创建新的对象。
不必考虑到线程同步问题,我们应该优先使用StringBuilder类;如果要保证线程安全,自然是StringBuffer。
Object
在Object类中主要包括clone()、finalize()、equals()、toString()等方法,其中常用的两个方法为equals()和toString()方法。
Object类中的getClass()、notify()、notifyAll()、wait()等方法不能被重写,因为这些方法被定义为final类型。
异常
Error 和 Exception的区别
1 | Exception是java程序运行中可预料的异常情况,咱们可以获取到这种异常,并且对这种异常进行业务外的处理。 |
Exception
1 | 其中的Exception又分为检查性异常和非检查性异常。两个根本的区别在于,检查性异常 必须在编写代码时,使用try catch捕获(比如:IOException异常)。非检查性异常 在代码编写使,可以忽略捕获操作(比如:ArrayIndexOutOfBoundsException),这种异常是在代码编写或者使用过程中通过规范可以避免发生的。 |
它处理的是因为程序设计的瑕疵而引起的问题或者在外的输入等引起的一般性问题,是程序必须处理的。
Error
1 | 表示系统级的错误和程序不必处理的异常,如:OutOfMemoryError、NoClassDefFoundError等。 |
受检异常和非受检异常
非受检异常指的是java.lang.RuntimeException和java.lang.Error类及其子类,所有其他的异常类都称为受检异常。
以下是RuntimeException 非受检异常
Java.lang.ClassCastException
Java.lang.IllegalArgumentException
Java.lang.IndexOutOfBoundsException
Java.lang.ArrayIndexOutOfBoundsException
Java.lang.NullPointerException
throw和throws的区别
1、throw代表动作,表示抛出一个异常的动作;throws代表一种状态,代表方法可能有异常抛出
2、throw用在方法实现中,而throws用在方法声明中
3、throw只能用于抛出一种异常,而throws可以抛出多个异常
什么是Java EE
Java 平台企业版
JavaEE 与 JavaSE 的区别与联系
JavaEE 是在 JavaSE 的基础上构建的,是对 JavaSE 的扩展,增加了一些更加便捷的应用框架。
JavaEE主要技术
JDBC Servlet jsp XML
反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
如何通过反射创建对象
通过类对象调用newInstance()方法
通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象
JDBC执行步骤
- 注册驱动
- 建立连接
- 创建statement语句对象
- 执行sql语句
- 处理返回的结果
- 关闭连接
什么是JDBC,在什么时候会用到它?
JDBC的全称是Java DataBase Connection,也就是Java数据库连接,我们可以用它来操作关系型数据库。JDBC接口及相关类在java.sql包和javax.sql包 里。我们可以用它来连接数据库,执行SQL查询,存储过程,并处理返回的结果。
JDBC接口让Java程序和JDBC驱动实现了松耦合,使得切换不同的数据库变得更加简单。
array和arrayList有什么区别
ArrayList可以算是Array的加强版,(对array有所取舍的加强)。
array长度固定,arrayList长度可变;
ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
Queue
在处理元素前用于保存元素的 collection。除了基本的 Collection
操作外,队列还提供其他的插入、提取和检查操作。每个方法都存在两种形式:一种抛出异常(操作失败时),另一种返回一个特殊值(null
或 false
,具体取决于操作)。插入操作的后一种形式是用于专门为有容量限制的 Queue
实现设计的;在大多数实现中,插入操作不会失败。
Queue 中 poll()和 remove()有什么区别
poll()在队列为空时返回null,而remove()会抛出NoSuchElementException异常。
抛出异常 | 返回特殊值 | |
---|---|---|
插入 | add(e) |
offer(e) |
移除 | remove() |
poll() |
检查 | element() |
peek() |
Spring用了哪些模式
- 工厂模式
- 单例模式
- 策略模式
- 代理模式
- 模版模式
- 适配器模式
- 观察者模式
Spring 中使用了哪些设计模式?
- 工厂模式:spring中的BeanFactory就是简单工厂模式的体现,根据传入唯一的标识来获得bean对象;
- 单例模式:提供了全局的访问点BeanFactory;
- 代理模式:AOP功能的原理就使用代理模式(1、JDK动态代理。2、CGLib字节码生成技术代理。)
- 装饰器模式:依赖注入就需要使用BeanWrapper;
- 观察者模式:spring中Observer模式常用的地方是listener的实现。如ApplicationListener。
- 策略模式:Bean的实例化的时候决定采用何种方式初始化bean实例(反射或者CGLIB动态字节码生成)
代理模式是什么
为被代理对象提供一个代理对象,并由代理对象控制被代理对象的引用。
为什么要用代理模式?
中介隔离作用:
在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
三种代理模式
- 静态代理
- jdk动态代理
- cblib动态代理
单例模式是什么
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
单例模式的作用:
一是,解决多线程并发访问的问题。二是节约系统内存,提交系统运行的效率,提高系统性能。
什么是工厂模式
Spring使用工厂模式可以通过 BeanFactory
或 ApplicationContext
创建 bean 对象。
BeanFactory 和ApplicationContent的区别
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。
ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。
ApplicationContext:
应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能;
提供国际化的消息访问 (MessageSource)
访问资源,如URL和文件(ResourceLoader)
载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
消息发送、响应机制(ApplicationEventPublisher)
AOP(拦截器)
事件传播
数据库中有哪些约束
- 主键约束(Primay Key Coustraint) 唯一性,非空性
- 唯一约束 (Unique Counstraint)唯一性,可以空,但只能有一个
- 外键约束 (Foreign Key Counstraint)需要建立两表间的关系并引用主表的列
- 检查约束 (Check Counstraint)对该列数据的范围、格式的限制(如:年龄、性别等)
- 默认约束 (Default Counstraint)该数据的默认值
怎么设置约束
Servlet的执行流程
- 客户端发送请求给服务器。
- 服务器开始接受,先判断该请求的servlet实例是否存在,如果不存在先装载一个servlet类并创建实例,调用init方法进行初始化。如果存在则直接调用该servlet的service方法,之后进行判断是调用doGet方法还是doPost方法。
- 最后判断服务是否关闭,如果关闭则调用destroy方法。
Servlet的生命周期
init()
service()
destroy()
关系型数据库和非关系型数据库有什么区别
关系型数据库 有MySQL
SQLServer
MariaDB
oracle
SQLite
关系型和非关系型数据库的主要差异是数据存储的方式。关系型数据天然就是表格式的,因此存储在数据表的行和列中。数据表可以彼此关联协作存储,也很容易提取数据。
优点:
1、易于维护:都是使用表结构,格式一致;
2、使用方便:SQL语言通用,可用于复杂查询;
3、复杂操作:支持SQL,可用于一个表以及多个表之间非常复杂的查询。
缺点:
1、读写性能比较差,尤其是海量数据的高效率读写;
2、固定的表结构,灵活度稍欠;
3、高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。
非关系型数据库 有 Redis
MongoDB
优点:
1、格式灵活:存储数据的格式可以是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。
2、速度快g:nosql可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘;
3、高扩展性;
4、成本低:nosql数据库部署简单,基本都是开源软件。
缺点:
1、不提供sql支持,学习和使用成本较高;
2、无事务处理;
3、数据结构相对复杂,复杂查询方面稍欠。
配置SpringBean的几种方式
有三种方式
- 传统的XML配置方式
- 基于Java注解的配置
- 基于类的Java Config类
Seralizable
Serializable是一个标识性接口,Java编译器在编译实现序列号接口的类的时候,会自动插入三个方法,这三个方法会自动完成对象的序列号与反序列化,在序列化时,Java的对象输入输出流,会自动调用这三个方法
get和post的区别
GET参数通过URL传递,POST放在Request body中。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求在URL中传送的参数是有长度限制的,而POST没有。
Spring中的bean是线程安全的吗
Spring容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性
如果单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。
对于有状态的bean,Spring官方提供的bean,一般提供了通过ThreadLocal去解决线程安全的方法,因为ThreadLocal为每个线程保存线程私有的数据。
Java中参数传递的规则只有一种
值传递
传递的是自身在栈中的值的拷贝,而不是自身在栈中的值的引用,既然是拷贝,那么不管怎么修改,都不会影响。
接口和抽象类
接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约,更像是一种规范。而抽象类在代码实现方面发挥作用,可以实现代码的重用。
抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
面向接口编程就是增强了代码的拓展性,而接口就是体现的一种规范,也是体现的一种拓展思想。
JSP
jsp中九个内置对象
request,response,session,application,page,out,config,pagecontext,exception
JSP四大作用域
page(只在当前页面有效), request(在当前请求中有效) ,session(在当前会话中有效), application(在所有的应用程序中都有效)
Java版本的区别
数据库引擎
InnoDB
- 默认事务型引擎,被广泛使用的存储引擎
- 支持行级锁
- 支持外键
- 主键查询的性能高于其他类型的存储引擎
- 数据存储在共享表空间,即多个表和索引都存储在一个表空间中,可通过配置文件修改
- 内部做了很多优化,如:从磁盘读取数据时会自动构建hash索引,插入数据时自动构建插入缓冲区
- 通过一些机制和工具支持真正的热备份
- 支持崩溃后的安全恢复
MyISAM
- 拥有全文索引、压缩、空间函数
- 不支持事务和行级锁、不支持崩溃后的安全恢复
- 表存储在两个文件:MYD 和 MYI
- 设计简单,某些场景下性能很好,例如获取整个表有多少条数据,性能很高
数据库的三范式是什么?有什么作用?
- 列不可分,确保表的每一列都是不可分割的原子数据项。作用:方便字段的维护、查询效率高、易于统计。
- 确保表中的每列都和主键相关,也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。(限制多对多的关系,建立一个关联表,通过外键和联合主键来关联两张表)
- 每一列数据都和主键直接相关,而不能间接相关,(限制一对多的关系,在从表中建立一个外键,通过外键来引用主表的信息)
Java Bean 是什么
1、所有属性为private
2、提供默认构造方法
3、提供getter和setter
4、实现serializable接口
Spring bean是什么
在 Spring 中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是一个由Spring IoC容器实例化、组装和管理的对象。
依赖注入有哪几种方式,有什么区别
三种依赖方式:构造方法注入、Setter方法注入与接口注入。
一、构造器注入
将被依赖对象通过构造函数的参数注入给依赖对象,并且在初始化对象的时候注入。
优点:
对象初始化完成后便可获得可使用的对象。
缺点:
- 当需要注入的对象很多时,构造器参数列表将会很长;
- 不够灵活。若有多种注入方式,每种方式只需注入指定几个依赖,那么就需要提供多个重载的构造函数,麻烦。
二、setter方法注入
IoC Service Provider通过调用成员变量提供的setter函数将被依赖对象注入给依赖类。
优点:
灵活。可以选择性地注入需要的对象。
缺点:
依赖对象初始化完成后由于尚未注入被依赖对象,因此还不能使用。
三、接口注入
依赖类必须要实现指定的接口,然后实现该接口中的一个函数,该函数就是用于依赖注入。该函数的参数就是要注入的对象。
优点
接口注入中,接口的名字、函数的名字都不重要,只要保证函数的参数是要注入的对象类型即可。
缺点:
侵入行太强,不建议使用
什么时候需要定义构造方法
通常,如果需要自定义构造方法,可能是因为:
创建对象的同时,快速的为属性赋值;
限制对象的创建过程,例如在单例模式的设计中,将构造方法声明为私有权限;
强制要求传入某些数据。
Iterator
获得一个类的类对象有哪些方式
类型.class
对象.getClass()
Class.forName()
如何通过反射创建对象
使用Class对象的newInstance()方法来创建对象
通过Constructor类的newInstance()方法获取
GC的执行流程
IOC
IOC的两种实现方式
依赖查找DL
依赖注入DI
IOC的功能有哪些
IOC的初始化过程
用户构造CLassPathXmlApplicationContext(简称CPAC)
低容器的IOC
高级容器低IOC
依赖注入构造器注入与set注入的区别
构造器注入的优点是对象在构造完成后,即已经进入就绪状态了,可以马上使用,缺点是,当依赖对象比较多时,构造方法的参数会比较长。
setter方法注入的优点是因为方法可以命名,在描述性上更强,setter方法可以被继承,允许设置默认值。灵活性更高。
(接口注入强制实现接口,带有侵入性)
Servlet的意义
其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。
Servlet的生命周期
Servlet调用init()初始化
Servlet调用service()处理请求
Servlet调用destroy()方法终止
Servlet响应流程
jsp与servlet的联系
jsp是servlet技术的扩展
jsp的内置对象
三次握手四次挥手
两次握手只能保证单向连接是畅通的。
只有经过第三次握手,才能确保双向都可以接收到对方的发送的 数据。
四次挥手
- 第一次:客户端请求断开FIN,seq=u
- 第二次:服务器确认客户端的断开请求ACK,ack=u+1,seq=v
- 第三次:服务器请求断开FIN,seq=w,ACK,ack=u+1
- 第四次:客户端确认服务器的断开ACK,ack=w+1,seq=u+1
四次挥手时,当收到对方的 FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方 ACK 和 FIN 一般都会分开发送。
Spring IOC之容器扩展点
1.使用BeanPostProcessor来定制bean
2.使用BeanFactoryPostProcessor来自定义配置数据
3.使用一个工厂bean来定制实例化逻辑
Spring由哪些模块组成?
简单可以分成6大模块:
- Core
- AOP
- ORM
- DAO
- Web
- Spring EE
- JDBC
负载均衡和反向代理?
同步锁和互斥锁
【同步】:
是指散步在不同任务之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。最基本的场景就是:两个或两个以上的进程或线程在运行过程中协同步调,按预定的先后次序运行。比如 A 任务的运行依赖于 B 任务产生的数据。
【互斥】:
是指散步在不同任务之间的若干程序片断,当某个任务运行其中一个程序片段时,其它任务就不能运行它们之中的任一程序片段,只能等到该任务运行完这个程序片段后才可以运行。最基本的场景就是:一个公共资源同一时刻只能被一个进程或线程使用,多个进程或线程不能同时使用公共资源。
springbean的注入过程
获取 BeanName,对传入的 name 进行解析,转化为可以从 Map 中获取到 BeanDefinition 的 bean name。
合并 Bean 定义,对父类的定义进行合并和覆盖,如果父类还有父类,会进行递归合并,以获取完整的 Bean 定义信息。
实例化,使用构造或者工厂方法创建 Bean 实例。
属性填充,寻找并且注入依赖,依赖的 Bean 还会递归调用 getBean
方法获取。
初始化,调用自定义的初始化方法。
获取最终的 Bean,如果是 FactoryBean 需要调用 getObject 方法,如果需要类型转换调用 TypeConverter 进行转化。
缓存击穿和缓存穿透
TOP命令
Spring、设计模式、AOP项目