快捷搜索:  汽车  科技

面试常见问题汇总(你真的准备好了吗)

面试常见问题汇总(你真的准备好了吗)1. 用户向服务器发送请求,请求被 Spring 前端控制 Servelt ---DispatcherServlet 捕获;所谓并发是指大量用户同一时刻读写同一条数据,那关键点就在于读和写。什么是并发:所谓并发操作是指在同一时间可能有多个用户对同一数据进行读写操作.并发问题的瓶颈在哪儿,读和写。怎么解决并发:

1.1.1.祝你好运

准备换一份工作你的真的准备好了吗,朋友送的一份面试资料,本文搞为初稿大致看过,有时间在持续修正更新



面试常见问题汇总(你真的准备好了吗)(1)

1.1.2. 开发流程

面试常见问题汇总(你真的准备好了吗)(2)

1.1.3. 并发

什么是并发:所谓并发操作是指在同一时间可能有多个用户对同一数据进行读写操作.

并发问题的瓶颈在哪儿,读和写。

怎么解决并发:

所谓并发是指大量用户同一时刻读写同一条数据,那关键点就在于读和写。

1. 用户向服务器发送请求,请求被 Spring 前端控制 Servelt ---DispatcherServlet 捕获;

2. DispatcherServlet 对请求 URL 进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用 HandlerMapping 获得该 Handler 配置的所有相关的对象(包括Handler 对象以及 Handler 对象对应的拦截器),最后以 HandlerExecutionChain 对象的形式返回;

3. DispatcherServlet 根据获得的 Handler,选择一个合适的 HandlerAdapter。(附注:如果成功获得 HandlerAdapter 后,此时将开始执行拦截器的 preHandler(...)方法)

4. 提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller)。 在填充 Handler 的入参过程中,根据你的配置,Spring 将帮你做一些

额外的工作:

HttpMessageConveter: 将请求消息(如 Json、xml 等数据)转换成一个对

象,将对象转换为指定的响应信息

数据转换:对请求消息进行数据转换。如 String 转换成 Integer、Double 等

数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等

数据验证: 验证数据的有效性(长度、格式等),验证结果存储到 BindingResult或 Error 中

5. Handler 执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象;

6. 根据返回的 ModelAndView,选择一个适合的 ViewResolver(必须是已经注册到Spring 容器中的 ViewResolver)返回给 DispatcherServlet ;

7. ViewResolver 结合 Model 和 View,来渲染视图

8. 将渲染结果返回给客户端。

1.2.4. Hibernate

优点:

对象/关系数据库映射(ORM),使用时只需要操作对象,完全面向对象的思想。

封装了 jdbc 的底层代码,不需要和 jdbc api 打交道即可直接访问数据库,在大型项目中开发效率高。

封装了很多可操作数据库的方法,不需要写 sql 语句。

提供一二级缓存。

缺点:

执行效率低,很多 sql 语句都是自动生成的,会有冗余语句,优化负责,更消耗内存。

多表和复杂数据的操作比较麻烦。

更适合单一对象的操作,不适合批量操作。

和 mybatis 的比较:

1、MyBatis 容易掌握,而 Hibernate 门槛较高。

2、Mybatis 基于原生的 jdbc 运行速度比 hinernate 更高。

3、针对高级查询,Mybatis 需要手动编写 SQL 语句,以及 ResultMap。而 Hibernate 有良好的映射机制,开发者无需关心 SQL 的生成与结果映射,可以更专注于业务流程。

4、Hibernate 数据库移植性很好,MyBatis 的数据库移植性不好,不同的数据库需要写不同 SQL。

1.2.5. Spring

Spring IOC:

所谓控制反转,举个例子:

遵循 mvc 的开发原则,我们在 web 层创建业务层对象时如下:

UserService userService=new UserService ();

但是这样写死的话不利于扩展和维护。而为了利于扩展功能,因此我们会写一个接口比如 userService 然后再通过父类引用子类对象的多态原则使程序有更好的扩展性:

UserService userService=new UserServiceImpl().但这种写法还是耦合性太高,如果有一天我要更换实现类,还是需要修改原代码,这样就违法了 OCP 原则(open-close 原则,该原则建议不要修改原代码,可以通过添加新的代码,实现新的功能,即对修改关闭,对扩展开放)。

那么为了实现 service 层和 web 层的解耦,我们就使用了工厂方式:

面试常见问题汇总(你真的准备好了吗)(3)

但是如此一来,工厂和实现类又耦合了,那么是否可以使工厂和实现类解耦呢。可以通过反射和配置文件:

面试常见问题汇总(你真的准备好了吗)(4)

而 IOC 能做到什么呢,就是 service 不再利用 web 层去获取,而是通过 spring 容器创建bean 对象来自动的为我们注入。这样的话整个过程就反过来了,以前是 web 层去 new 一个service 现在是 service 主动被设置到 web 层中去了,这就是反转控制的由来。

通过 IOC,我们就可以在不修改任何代码的情况下,就可以进行实现类的切换,当然前提还是必须得写一个 service 的实现类。这样我们只需要在配置文件配置一下就 ok 了,而不需要再一个个的写工厂来获取了。

这就是 IOC 为我们带来的模块的松耦合和应用的便利性。

DI 注入:

依赖注入,在 spring 框架创建 bean 对象时,动态的动态的将依赖对象注入到 bean 组件。

举例:HelloServiceImpl 内部需要依赖 info 属性

面试常见问题汇总(你真的准备好了吗)(5)

传统方法和依赖注入的区别:

面试常见问题汇总(你真的准备好了吗)(6)

IOC 和 DI 的区别:

IOC 控制反转指的是对象的创建权,被反转到了 spring 容器来管理。DI 依赖注入,指spring 容器在创建对象的过程中将对象依赖的属性通过配置文件进行注入。表面是先有控制反转,再有依赖注入。实际是一个事件,两种不同时期的称呼。DI 实际上也可以理解为就是实现 IOC 的方式。就比如将一个 B 对象注入到另外一个 A对象中,即实现了控制反转(不再在 A 对象中创建 B 对象,而是通过配置文件主动配置),也实现了 DI 注入(将 B 对象作为 A 对象的属性,利用配置文件注入到 A 对象中)。

Spring AOP:

AOP 的意思就是面向切面编程,AOP 采取横向抽取机制,取代了传统纵向继承体系重复性代码。实际上就是利用动态代理对目标对象中的方法进行增强JDK 的动态代理要求被代理对象必须实现接口。Cglib 则不需要。AOP 的底层实际上是实现了 JDK 和 CGLIB 两种代理机制。如果目标对象实现了接口,那么优先使用 JDK 的动态代理,如果没有实现任何接口,就会使用 CGLIB 库生成目标对象的子类作为代理对象。

1.3. 数据库面试问题

1.3.1. Mysql 的数据库引擎

Innodb 引擎

Innodb 引擎提供了对数据库 ACID 事务的支持,并且实现了 SQL 标准的四种隔离级别,关于数据库事务与其隔离级别的内容请见数据库事务与其隔离级别这篇文章。该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它本身其实就是基于 MySQL 后台的完整数据库系统,MySQL 运行时 Innodb 会在内存中建立缓冲池,用于缓冲数据和索引。但是该引擎不支持 FULLTEXT 类型的索引,而且它没有保存表的行数,当SELECT COUNT(*) FROM TABLE 时需要扫描全表。当需要使用数据库事务时,该引擎当然是首选。由于锁的粒度更小,写操作不会锁定全表,所以在并发较高时,使用 Innodb 引擎会提升效率。但是使用行级锁也不是绝对的,如果在执行一个 SQL 语句时 MySQL 不能确定要扫描的范围,InnoDB 表同样会锁全表。

MyIASM 引擎

MyIASM 是 MySQL 默认的引擎,但是它没有提供对数据库事务的支持,也不支持行级锁和外键,因此当 INSERT(插入)或 UPDATE(更新)数据时即写操作需要锁定整个表,效率便会低一些。不过和 Innodb 不同,MyIASM 中存储了表的行数,于是 SELECT COUNT(*)FROM TABLE 时只需要直接读取已经保存好的值而不需要进行全表扫描。如果表的读操作远远多于写操作且不需要数据库事务的支持,那么 MyIASM 也是很好的选择。两种引擎的选择大尺寸的数据集趋向于选择 InnoDB 引擎,因为它支持事务处理和故障恢复。数据库的大小决定了故障恢复的时间长短,InnoDB 可以利用事务日志进行数据恢复,这会比较快。主键查询在 InnoDB 引擎下也会相当快,不过需要注意的是如果主键太长也会导致性能问题,关于这个问题我会在下文中讲到。大批的 INSERT 语句(在每个 INSERT 语句中写入多行,批量插入)在 MyISAM 下会快一些,但是 UPDATE 语句在 InnoDB 下则会更快一些,尤其是在并发量大的时候。

1.3.2. SQL 优化

1. 对操作符的优化 尽量不采用不利用索引的操作符

如:in ,not in , is null, is not null,<> like 等

2. select count(*) from table;这样不带任何条件的 count 会引起全表扫描,并且没有任何

业务意义,是一定要杜绝的。

3. 使用“临时表”暂存中间结果

部分 UPDATE、SELECT 语句 写得很复杂(经常嵌套多级子查询)——可以考虑适当拆成几步,先生成一些临时数据表,再进行关联操作。简化 SQL 语句的重要方法就是采用临时表暂存中间结果,但是,临时表的好处远远不止这些,将临时结果暂存在临时表,后面的查询就在 tempdb 中了,这可以避免程序中多次扫描主表,也大大减少了程序执行中“共享锁”阻塞“更新锁”,减少了阻塞,提高了并发性能。

4. 排序

避免使用耗费资源的操作,带有 DISTINCT UNION MINUS INTERSECT ORDER BY 的 SQL语句会启动 SQL 引擎 执行,耗费资源的排序(SORT)功能. DISTINCT 需要一次排序操作 而其他的至少需要执行两次排序

1.3.3. 如何快速向表中插入 100 万条数据

1、Mysql 中有 LOAD DATA INFILE 语句用于高速地从一个文本文件中读取行,并装入一个表中。文件名称必须为一个文字字符串。

2、批量插入

面试常见问题汇总(你真的准备好了吗)(7)

1.4. java 基础

1.4.1. Error 和 Exception 的区别

Error:表示 Java 程序中存在的那些错误现象,而这些错误现象统一使用 Error 进行描述。在我们的程序中,如果发生 Error 问题,我们不会去处理这样的问题,而是让程序的定义者自己去处理自己程序中的错误。针对 Error 我们不给出程序的针对性处理。

Exception:表示 Java 程序中存在的异常问题。而不是错误问题。而这些异常问题,在程序中通过

判断等形式是可以检测并且预防的。而针对这些异常问题,程序员在写代码的时候一旦发生必须给出有效的解决方案。

1.4.2. 垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么方法可以通知 jvm 进行垃圾回收?

答:对象刚创建,GC 就开始监控这个对象的地址、大小以及使用情况。通常,GC 采用有向图的方式记录和管理(heap)堆中所有对象。通过这种方式确定哪些对象时可达的,哪些是不可达的,当确定一些对象不可达,GC 就有责任回收这些内存空间。可以。手动执行 System.gc() 通知 GC 运行,但是 java 语言规范并不保证 gc 一定运行。

1.4.3. 抽象类和接口的区别?什么时候用抽象类,什么时候用接口?

答:

含有 abstract 修饰符的类就是抽象类,抽象类不能创建实例对象。含有抽象方法的类必须是抽象类,抽象类中可以有非抽象方法。

子类在继承抽象类时,必须重写抽象类的所有抽象方法。不能有抽象构造方法和抽象静态方法。如果子类没有实现抽象类中的所有抽象方法,那么子类也必须是抽象的。

接口是抽象类的一种特例,接口中的方法都是抽象方法,接口中的变量都要用 public static final 修饰。

两者的区别:

1.抽象类中可以有构造方法,接口中没有构造方法

2.抽象类中有普通的成员变量,接口中没有普通成员变量。

3.抽象类中可以有非抽象方法,接口中不能有非抽象方法。

4.抽象类中抽象方法的访问类型可以是 public protected,但是接口中只能是 public

5.抽象类中可以有静态方法,接口中不能有静态方法。

6.抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,

但是接口中必须是 public static fianl。

7.一个类可以实现多个接口,但是只能继承一个抽象类

应用上的不同:

接口更多的是在系统架构设计方法上发挥作用,主要用于定义模块之间的通信契约和扩展功能。

而抽象类在代码实现方面发挥作用,可以实现代码的重用。比如我们项目中三层开发中的 dao 层和 service 层,会创建一个接口,然后定义一个接口类,主要是考虑到多实现。

在 mybatis 的时候,我们操作数据库,会封装一些方法到一个抽象类中,然后由 service 层来继承这个抽象类,就可以复用里面的方法,方便开发。

1.4.4. 是否可以继承 String 类?

不可以,因为 String 类被 final 修饰。

1.4.5. String 和 StringBuffer 的区别?

1.String 数值不可变,StringBuffer 字符串长度可变。

2.String 覆盖了 equals 和 hashCode 方法,StringBuffer 没有覆盖 equals 和 hashCode 方法。

1.4.6. final、finalize 和 finally 的区别

final 用于声明属性,方法和类的

finally 是异常处理语句结够的一部分,表示总是执行。

finalize 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法

1.4.7. 多线程有几种实现方法?同步有几种实现方法?

多线程有两种实现方法:继承 Thread 类和实现 Runnable 接口。

1.4.8. 简述一下线程的几种可用状态;

线程在执行过程中,可以处于下面几种状态:

1、就绪(Runnable):线程准备运行,不一定立马就能开始执行。

2、运行中(Running):进程正在执行线程的代码。

3、等待中(Waiting):线程处于阻塞的状态,等待外部的处理结束。,

4、睡眠中(Sleeping):线程被强制睡眠。

5、I/O 阻塞(BlockedonI/O):等待 I/O 操作完成。

6、同步阻塞(BlockedonSynchronization):等待获取锁。

7、死亡(Dead):线程完成了执行。

1.4.9. 什么是 java 序列化,如何实现 java 序列化?或者请解释 serializable 的作用.

序列化:就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。

序列化的实现:将需要被序列化的类实现 Serializable 接口,然后使用一个输出(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象,接着使用 ObjectOutputStream 对象的writeObject(Object obj)方 法就 可以 将参数 为 obj 的 对象 写出(即 保存其 状态), 要恢 复的话则 用输 入流ObjectInputStream。

1.4.10. session 共享的几种方式?

1.写客户端 cookie 的方式

当用户登陆成功以后,把网站域名、用户名、密码、token、session 有效时间全部采用 cookie的形式写入到客户端的 cookie 里面,如果用户从一台 Web 服务器跨越到另一台服务器,我们的程序主动去检测客户端的 cookie信息,进行判断,然后提供对应的服务。当然,如果 cookie 过期或者无效,自然就不让用户继续服务了。当然,这种方法的弊端就不言而喻了,比如客户端禁用了cookie 或者 cookie 被黑客窃取了呢?

2.服务器之间 Session 数据同步的方式

假设 Web 服务器 A 是所有用户登陆的服务器,那么当用户验证登陆一下,session 数据就会写到 A 服务器里,那么就可以自己写脚本或者守护进程来自动把 session 数据同步到其他 Web 服务器,那么当用户跳转到其他服务器的时候,那么 session 数据是一致的,自然就能够直接进行服务无须再次登陆了。缺点是,可能会速度慢,不稳定。如果是单向同步的话,登陆服务器出现问题,那么其他服务器也无法服务,当然也可以考虑双向同步的问题。

3.利用 NFS 共享 Session 数据的方式

大致就是有一台公共的 NFS 服务器(Network File Server)做共享服务器,所有的 Web 服务器登陆的时候把 session 数据写到这台服务器上,那么所有的 session 数据其实都是保存在这台 NFS 服务器上的,不论用户访问哪台 Web 服务器,都要来这台服务器获取 session 数据,那么就能够实现共享 session 数据了。缺点是依赖性太强,如果 NFS 服务器挂掉了,那么大家都无法工作了。当然,可以考虑多台 NFS 服务器同步的形式。

4. 利用 Mysql 数据库共享 Session 数据的方式(我们可以使用 Redis)

这个方式与 NFS 的方式类似,也是采用一台 Mysql 服务器做共享服务器,把所有的 session的数据保存到 Mysql 服务器上,所有 Web 服务器都来这台 Mysql 服务器来获取 Session 数据。缺点也是依赖性太强,Mysql无法工作了影响所有的 Web 服务器。当然,可以考虑多台 Mysql 数据库来共享 session,使用同步 Mysql 数据的方式。

5.使用硬件设备

这个算是比较成熟的解决方案了,使用类似 BIG-IP 的负载设备来实现资源共享,那么就能够又稳定又合理的的共享 Session 了。目前很多门户网站采用这种方式。缺点很明显了,就是要收费了,硬件设备肯定需要购买成本的,不过对于专业或者大型应用来讲,是比较合理并且值得的

1.4.11. Ajax 同步与异步的区别

异步传输方式是用的最多的也是默认的方式,他避免了服务器检索给用户带来的时间延迟。在异步传输时候,它只是在后面悄悄进行着,用户仍旧可以做他做的事情,不会给用户任何的等待的感觉。在传输的数据量较大的时候,服务器检索的时间就更长了,但是用户却不知道,用户仍旧专注于页面上面的操作,根本就不知道服务器都干了些什么,就给用户良好的体验。同步传输方式却相反,他就好像是刚刚加载页面的那一刻一样,当发出了同步请求之后,浏览器就在等待,等待服务器检索完毕,返回结果。此时,鼠标会变成等待的形状,提醒我们的用户请求还没有相应,您什么也不能做,我们的用户就什么也干不成,能够做的一件事就是——等待……虽然用户已经习惯了等待整改页面的加载,虽然在 ajax 里面同步请求的时间一般不会大于整个页面加载的时间,但是你要知道什么都不做只是在那里被动等待是多么痛苦的一件事情。所以,这个同步请求要慎重使用……

1.4.12. 简单描述一下 List、Map 和 Set 的区别;

1.Set 接口:有两个实现类(HashSet(底层由 HashMap 实现),LinkedHashSet)

2.List 接口:有三个实现类(LinkedList:基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址。链表增删快,查找慢;

ArrayList:非线程安全的,效率高;基于数组;便于索引,但不便于插入删除

Vector:基于线程安全的,效率低;基于数组; )

3.Map 接口:有三个实现类(HashMap,HashTable,LinkedHashMap,TreeMap)

HashMap:非线程安全,高效,支持 null;

HashTable:线程安全,低效,不支持 null;

LinkedHashMap:非线程安全,是 HashMap 的一个子类,保存了记录的插入顺序

TreeMap:该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序

1.4.13. JAVA 中的方法覆盖(Overriding)和方法重载(Overloading)是什么意思?

覆盖是 override 方法-重写 重载是 overload按照教科书上的定义,重载就是具有相同函数名,返回类型可以不同,参数个数、顺序、类型不同的函数。我的理解是重载是发生在两个或者是更多的函数具有相同的名字的情况下。

重写就是覆盖父类的方法,和父类有相同返回类型,参数,甚至是抛出的异常,重写方法不能为 private,运用中最典型的就是对接口方法的覆盖。

猜您喜欢: