前言:
我想每个程序员比较头疼的事情都是:工作拧螺丝,面试造火箭吧。但是又必须经历这个过程,尤其是弄不清面试官问的问题,如果你准备的不是很充分,会导致面试的时候手足无措。今天这篇文章是从已工作5年的程序员面试几十次中挑选的面试概率比较大的一些题目,都是大家被问到过的(就是这么自信),希望这篇文章能够对大家找工作有所帮助。
基础部分
一丶抽象类和接口的区别
1.语法区别
(1)抽象类可以有构造方法,接口不能有构造方法;
(2)抽象类中可以有普通成员变量,接口中没有普通成员变量;
(3)抽象类中可以有非抽象的方法,接口中的方法都必须是抽象的;
(4)抽象类中的方法可以是public,protected类型,接口中的方法只能是public类型的,切 默认为public abstract类型;
(5)抽象类中可以有静态方法,接口中不能有静态方法;
(6)抽象类中的静态变量访问类型可以是任意的,但接口中的静态变量只能是public static final 类型。
(7).一个类可以实现多个接口,但一个类只能继承一个抽象类;
2.应用区别
接口更多是在系统架构方面发挥作用,主要用于定义模块之间的通信契约;而抽象类在代码方法 发挥作用,可以使用代码块的重用;
二丶Java中接口可不可以继承一般类,为什么?
不可以因为接口中只能出现3种成员
1.公共的静态常量(public static final )
2.公共的抽象方法(public abstract )
3.静态内部类(static class)
而一个类中,就算什么都不写,也必须带一个构造方法,在extends时就会被子类继承,如果是接口也会 继承这个构造方法,很明显构造方法不在上面三项之列
而如果类中有一般的方法和成员变量,也会被子类全部继承,这些更不能出现在接口中了,所以接口是绝 对不可能继承一个类的
三、基本数据类型的默认值?基本数据类型所占的字节
1. 默认值
(1)byte、short、int、long的默认值为0
(2)float、double默认值为0.0
(3)char默认值为空
(4)boolean默认值为false
2.所占字节
(1)byte 1个字节
(2)short 2个字节
(3)char 2个字节
(4)int 4个字节
(5)long 8个字节
(6)float 4个字节
(7)double 8个字节
四丶String属于那个类,以及常用的方法
1.java.lang.string
2.substring(),indexOf(),concat(),endswith(),length(),replace()
五丶熟悉的网络协议
1.TCP/IP协议是一种面向连接的、可靠的协议。
TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层,每层分别负责不同的通信功能,接下来针对这四层进行详细地讲解。
链路层:用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。
网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。
传输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。
应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。
2.FTP 文件传输协议,允许在网络上传输文件。
六、String、StringBuffer、StringBuilder
String的值是不可改变的,这就导致每次对String的操作都会生成新的String对象,不禁效率底下, 而且浪费大量的内存空间;StringBuilder是可变类,任何对他指向的字符串的操作都不会产生新的对 象,但单线程不安全;StringBuffer底层方法使用了synchronized关键字,线程比较安全,但效率 较StringBuilder慢;
七、设计模式
单例模式:某个类只能有一个实例,提供一个全局的访问点;
工厂模式:定义一个创建对象的接口,让子类决定实例化那个类;
代理模式:为其他对象提供一个代理以便控制这个对象的访问;
八、高并发如何处理?
1.从最基础的地方做起,优化我们写的代码,减少必要的资源浪费。
a.避免频繁的new对象,对于整个程序只需要一个实例的类,我们可以使用单例模式;对于String 链接操作,使用StringBuffer或StringBuilder,对于工具类可以通过静态方法来访问;
b.避免使用错误的方式,使用java中高效率的类,比如ArrayList比Vector性能好;
2.html静态化
把一些经常不改变的内容静态化,高并发时减少服务器的压力;
3.图片服务器分离
对于web服务器来说,图片是最消耗资源的,于是我们把图片放到独立的服务器,这样可以降低 页面请求服务器的系统压力;
4.缓存
避免每一次都去数据库中去查询,减少数据库的访问量;并且使用redis数据库来做缓存,它的 读写速度是非常快的;
5.数据库优化
(1)优化sql语句
a.Select语句必须指定列名
b.当查询结果为一条时,使用limit 1
c.避免使用%前缀搜索,避免全表扫描
九、get与post的区别
GET在浏览器回退时是无害的,而POST会再次提交请求。 GET产生的URL地址可以被Bookmark,而POST不可以。 GET请求会被浏览器主动cache,而POST不会,除非手动设GET请求只能进行url编码,而POST支持多种编码方式。 GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。 GET请求在URL中传送的参数是有长度限制的,而POST么有。 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。 GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。 GET参数通过URL传递,POST放在Request body中。
十、JDK1.8新特性
- 提供lambda表达式极大地减少了代码的冗余;
- 在接口中可以使用default和static关键字来修饰接口中的普通方法;
- 提供新的API LocalDate | LocalTime | LocalDateTime
(1)Java.util.Date和SimpleDateFormatter线程上都不安全,而LocalDate和LocalTime和 String一样都是不可改变类,线程上比较安全,还不能修改;
(2)Java.util.Date月份从0开始,12月是11,而java.time.LocalDate月份和星期都改成了 enum, 就不可能出错了;
集合部分
一、List、Map、Set三个接口,存取元素时,各有什么特点
(1)Set集合的add有一个boolean类型的返回值,当集合中没有某个元素时,则可以成功加入该 元素,返回结果为true;当集合中存在与某个元素equals方法相等 的元素时,则无法加入该元素, 取元素时只能用Iterator接口取得所有元素,在逐一遍历各个元素;
(2)List表示有先后顺序的集合,调用add()方法,指定当前对象在集合中的存放位置;一个对象可 以被反复存进集合中;每调用一次add()方法,该对象就会被插入集合中一次,其实,并不是把对 象本身存进了集合中,而是在集合中使用一个索引变量指向了该对象,当一个对象被add多次时, 即有多个索引指向了这个对象。List去元素时可以使用Iterator取出所有元素,在逐一遍历,还可 以使用get(int index)获取指定下表的元素;
(3)Map是双列元素的集合,调用put(key,value),要存储一对key/value,不能存储重复的key, 这个是根据eauals来判断;取元素时用get(key)来获取key所对 应的value,另外还可以获取 全部key,全部value
二、ArrayList和LinkedList的底层实现原理?他们为什么线程不安全?在多线程并发操作下,我们应该用什么替代?
1.ArrayList底层通过数组实现,ArrayList允许按序号索引元素,而插入元素需要对数组进行移位等内存操作,所以索引快插入较慢;(扩容方式)一旦我们实例化了ArrayList 无参构造函数默认数组长度为10。add方法底层如 果增加的元素超过了10个,那么ArrayList底层会生成一个新的数组,长度为原来数组长度的1.5倍+1,然后将原数组内容复制到新数组中,并且后续加的内容都会放到新数组中。当新数组无法容纳增加元素时,重复该过程;
2.LinkedList底层通过双向链表实现,取元素时需要进行前项或后项的遍历,插入元素时只需要记录本项的前后 项即可,所以插入快查询慢;
3.ArrayList和LinkedList底层方法都没有加synchronized关键词,多线程访问时会出现多个线程先后更改数据造成得到的数据是脏数据;多线程并发操作下使用Vector来代替,Vector底层也是数组,但底层方法都加synchronized关键字使线程安全,效率较ArrayList差;
三、HashMap和HashTable有什么区别?其底层实现是什么?CurrentHashMap的锁机制又是如何?如果想将一个Map变为有序的,该如何实现?
1.区别:
(1)HashMap没有实现synchronized线程非安全,HashTable实现了synchronized线程安全;
(2)HashMap允许key和value为null,而HashTable不允许
2.底层原理:数组+链表实现
3.ConcurrentHashMap锁分段技术:HashTable效率低下的原因,是因为所访问HashTable的线程都必须竞争同一把锁,那假如容器中有多把锁,每一把锁用于锁住容器中的一部分数据,那么当多线程访问容器中不同的数据时,线程间就不会存在锁竞争,从而提高并发访问率;ConcurrentHashMap使用的就是锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个数据时,其他段的数据也能被其他线程访问;
4.实现TreeMap
框架部分
一、什么是Spring
Spring是一个轻量级的开源框架,是为了解决企业应用开发的复杂性而创建的;提供IOC来帮住我们创建对象及管理对象之间的依赖关系,提供AOP来帮我们完成日志的打印、异常的处理、事物的管理等操作,提供JDBC、ORM来完成持久层的操作,内置SpringMvc控制层框架
二、spring优点
1:方便解耦,简化开发;
2:方便的对程序进行拦截、运行、监控等功能;
3:提供声明式事物;
4:属于一个万能的框架,跟很多框架都是百搭;
三、什么是IOC?什么是AOP?
(1)IOC称为控制反转是指在程序运行时自动注入依赖对象;
底层实现原理:反射机制
(2)AOP称为面向切面编程,就是程序中有很多各不想干的方法,在这些方法中加入
某种系统功能的代码;例如加入日志、加入异常处理、加入事物管理
底层实现原理:动态代理
四、反射机制:在程序运行时根据指定的类名获取类的信息;
主要作用:
1.在运行时构造一个类的对象;
2.判断一个类所具有成员变量和方法;
3.调用一个对象的方法;
4.生成动态代理;
五、动态代理:利用Java反射技术,在运行时创建一个实现某些给定接口的新类(又分为JDK动态代理和Cglib动态代理)
主要作用:
1.可以隐藏委托类(就是被代理类)的具体实现
2.可以实现客户与委托类间的解耦,再不修改委托类代码的情况下能够做一些额外的处理
JDK动态代理和Cglib动态代理的区别?
JDK动态代理只能对实现了接口的类生成代理,为不能针对类
Cglib动态代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(集成)
六、什么是DI机制?
依赖注入(Dependecy Injection)和控制反转(Inversion of Control)是同一个概念,具体的讲:当某个角色需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在spring中创建被调用者的工作不再由调用者来完成,因此称为控制反转。创建被调用者的工作由spring来完成,然后注入调用者,因此称为依赖注入;
七、Spring的Ioc注入方式有几种?
一、Set注入
二、构造器注入
三、接口注入
spring注入方便管理,依赖注入或者说是控制反转,说白了就是使用了配置文件,这种思想的唯一好处就是增加了模块的重用性灵活性。
八、hibernate的工作原理
1.通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件
2.由hibernate.cfg.xml中的读取并解析映射信息
3.通过config.buildSessionFactory();//创建SessionFactory
4.sessionFactory.openSession();//打开Sesssion
5.session.beginTransaction();//创建事务Transation
6.persistent operate持久化操作
7.session.getTransaction().commit();//提交事务
8.关闭Session
9.关闭SesstionFactory
九、hibernate优点:
1.对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
2.Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO 层的编码工作
3.hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
4.hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库, 从一对一到多对多的各种复杂关系。
十、SpringMvc运行流程
1.用户发送请求到DispatchServlet
2.DispatchServlet根据请求路径查询具体的Handler
3.DispatchServlet调用HandlerAdapter适配器,适配器再调用具体的Handler处理业务
4.Handler处理结束返回一个具体的ModelAndView给适配器,适配器将ModelAndView给 DispatchServlet
5.DispatchServlet把视图名称给ViewResolver视图解析器
6.ViewResolver视图解析器返回一个具体视图给DispatchServlet
7.将渲染视图的展示给用户
十一、ssh和是ssm的区别
SSH 通常指的是 Struts2 做控制器(controller),spring管理各层的组件,hibernate 负责持久化层。
SSM 则指的是 SpringMVC 做控制器(controller),Spring 管理各层的组件,MyBatis 负责持久化 层。
共同点:
1.Spring依赖注入DI来管理各层的组件。
2.使用面向切面编程AOP管理事物、日志、权限等。
不同点:
1.struts2和springmvc的区别;
2.hibernate和mybatis的区别;
十二、struts2和SpringMvc的区别?
1.springmvc入口是一个servlet前段控制器,struts2入口是一个filter过滤器;
2.springmvc是基于方法开发的,传递参数通过方法的形参来传递;struts2是基于类开发的,传递参 数通过类的属性来传递;
3.SpringMvc通过参数绑定期将request请求内容解析,并给方法形参赋值;struts2采用值栈存储 请求和响应数据,通过OGNL存储数据;
十三、hibernate和Mybatis的区别?
屏蔽jdbc的底层访问细节,使我们不与jdbc api打交道,就可以访问数据;jdbc api编程流程固定,还将sql语句与java代码混杂在了一起,经常需要拼凑sql语句,细节很繁 琐;iBatis提供了自动将结果集封装成实体对象和对象集合的功能,queryForList返回对象集合,用queryForObject返回单个对象,提供了将实体对象的属性传递给sql语句的参数;Hibernate是一个全自动的orm映射工具,他可以自动生成sql语句,ibatis需要我们自己在xml配置文件中写sql语句,hibernate要不ibatis负责功能强大很多。因为hibernate自动生成sql语句,不能写高效率的sql语句,对于一些不太复杂的sql查询hibernate可以很好的帮我们完成,特别复杂查询ibatis就比较合适了;
十四、Mybatis缓存机制?
缓存机制:Mybatis首先去缓存中查询结果集,如果没有则查询数据库,如果有则从缓存中取出返回结果集就不走数据库;
Mybatis的一级缓存是SqlSession级别的缓存,在操作数据库时需要创建SqlSession对象,在对象中有一个数据结构用于存储缓存的数据,不同的SqlSession之间的缓存互不影响并且不能互相读取;
Mybatis的二级缓存即查询缓存,它的作用域是一个mapper的namespace,即在同一个namespace中查询sql可以从缓存中获取数据,二级缓存是可以跨 SqlSession的;
MyBatis 默认没有开启二级缓存,开启只需在配置文件中写入如下代码:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
Web部分
一、JSP九大内置对象?作用分别是什么?分别有什么方法
request:用户端请求,此请求会包含来自GET/POST请求的参数
response:网页传回用户端的回应
pageContext:网页的属性是在这里管理
session:与请求有关的回话期
application servlet:正在执行的内容
out:用来传送回应的输出
page:JSP网页本身
config:servlet的构架部分
exception:针对错误网页,未捕捉的例外
request表示HttpServletRequest对象;它包含了有关浏览器请求的信息,并且提供了几个用于获取cookie,header和session数据的方法
response表示HttpServletResponse对象,并且提供了几个用于设置送回浏览器响应的方法
二、forward()与redirect()的区别?
forward是容器中控制权的转向,在客户端浏览器不会显示转向后的地址;redirect则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接,这样浏览器地址栏中就可以看到跳转后的链接地址。所以forward更加高效,在forward能满足需要时,尽量使用forward并且有助于隐藏实际的链接。如需要跳转到一个其他服务器上的资源,则必须使用redirect;
线程部分
1. 程序,进程,线程这三者之间的关系?
一个程序中可以调用多个进程,一个进程中可以有多个线程;比如一个视频播放器,里面就有两个进程:一个是播放视频的进程,一个是下载上传视频的进程;多个用户看视频就是多个线程访问一个进程;
2.单线程与多线程区别,以及多线程意义?
如果程序只有一条执行路径,这就是单线程;相反如果有多条路径,那就是多线程;
多线程的意义他可以让程序在一个时间执行多个事情,提高了应用程序的使用率;
3.理解并发与并行
并发:通过CPU调度算法,让用户看上去同时执行,实际上,是通过CPU再高速切换,并不是真正的同时,这就是并发;
并行:多个CPU实例或者多台机器同时执行一段逻辑,这就是真正的同时,这就是并行;
4.如何创建线程
方法一:
(1)类去继承Thread类;
(2)该类重写Thread类的run方法,并且将线程要执行的代码,存放到run方法中;
(3)线程对象调用start()方法,开启线程,线程会自动执行run方法
方法二
(1)类继承Runnable接口
(2)重写接口run方法,并将线程执行代码存放在run方法中
(3)创建Thread对象,也就是创建线程
(4)Thread线程对象调用start方法,启动线程
5.线程的几种状态?
初始化(new Thread()) --> 就绪(start()准备执行) --> 执行(获得CPU执行权)
执行1 --> 等待(wait()):线程处于等待状态,自己醒不了,只能用notify()或notifyAll()唤醒,处于等待状态的线程会释放CPU执行权,同时释放资源;
执行2 --> 睡眠(sleep()):在指定毫秒数内让当前正字执行的线程休眠,只是暂停执行,他会释放CPU执行权,但不会释放资源,设定时间到了,就会脱离睡眠状态,进入执行状态;
执行3 --> 阻塞:当多条线程存在输入输出时,就会出现阻塞状态
执行4 --> 死亡:run方法执行完毕,线程结束了也就是处于死亡状态
6.多线程解决方法
(1)同步代码块:代码块放入同步锁中
(2)同步方法:方法前加synchronized关键字
7.什么是死锁(deadlock)?
两个进程都在等待对象执行完后才继续往下执行的时候就发生了死锁,两个进程都陷入了无限的等待中;
数据库
一、你所了解的数据库优化方面有哪些?
1.Select语句必须指定字段名称
2.当只查询结果为一条数据时,使用limit 1
3.避免where子句对字段进行null值判断(对于null的判断会导致引擎放弃使用索引而进行全表扫描)
4.不建议使用%前缀模糊查询,防止全表扫描
二、事务的四大特征
1.原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚;
2.一致性(Consistency)
也就是说一个事物执行之前和执行之后都必须处于一致性状态;那转账来说,假设A和B两者的 钱一共是5000,不管A和B之间如何转账,转几次账,事务结束后两人的钱加起来还是5000,这就 是事务的一致性;
3.隔离性
隔离性当多个用户并发访问数据库并操作同一张表时,数据库为每一个用户开启的事务,不能被 其他事务操作所干扰,多个并发事务之间要相互隔离;比如两个并发事务T1和T2,在事务T1看来, T2要么在T1开始前结束事务,要么在T1结束后开始事务,这就是事务的隔离性;
4.持久性
执行性是指一个事务一但被提交了,那么对数据库中的数据的改变就是永久性的;
三、Spring隔离级别
- 如果多个事务同时访问相同数据时,如果没有采取必要的隔离级别,可能会发生什么问题?
(1)脏读:读取过期的数据,就是一个事物读到另一个事务未提交的新数据;
(2)幻读:读取临时的数据,就是一个事物在进行修改全表的时候,另一个事务对数据进行了新 增,从而第一个事务的执行完后发现还有没有修改的数据,就好像发生了幻觉一样;
(3)不可重复读:就是在同一个事务中先后执行两条一样的select语句,之间没有执行过Del 语句但先后结果不一样,这就是不可重复读; - Spring事务隔离级别
(1) Default:使用数据库本身的隔离级别ORACLE(读已提交)Mysql(可重复读);
(2) Read_Uncomited:读未提交(脏读),最低隔离级别,一切皆有可能;
(3) Read_Commited:读已提交,有幻读以及不可重复读的风险;
(4) RepeaTable_Read:可重复读,但还是有幻读风险;
(5) Serializable:串行化,最高隔离界别,杜绝一切隐患,但效率较低;
四、Spring怎么设置隔离级别?
- 用@Transactional注解声明式事务的事务管理中来设置isolation属性的隔离级别
- 在配置文件中设置事务tx:method元素
服务器
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。其特点是占有内存少,并发能力强,
Keepalived的作用是检测服务器的状态,如果有一台web服务器宕机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器。
Redis
1. 设置缓存值的过期时间?
(1) 常用的方式:expire key time(以秒为单位)
(2) 字符串独有方式:setex(String key,int seconds,String value)
如果没有设置时间,那缓存就是永不过期;
2. Redis三种过期策略
(1)定时删除:在设置key过期时间的同时,为该key创建一个定时器,让定时器在key过期的时候,对key进行删除;
(2)惰性删除:key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期删除,返回null;
(3)定期删除:每隔一段时间执行一次删除过期key的操作
总结:
针对于上面的面试题我总结出了互联网公司java程序员面试涉及到的绝大部分面试题及答案做成了文档和架构视频资料免费分享给大家(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术资料),希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习,也可以关注我以后会有更多干货分享。