脚本之家(jb51.cc)Java面试题栏目主要收集Java工程师面试题,Java人员面试专属面试题。
最近,各大公司开始了春招,很多人已经开始在准备面试了,特地来总结下初中级程序员应该掌握的面试题目。这篇面试指南,只适用于初中级程序员,其中不涉及分布式等问题。关于中高级的程序员问题,我后面可能再出一篇文章。对于一个初中级程序员来说,面试问题不仅仅涉及到Java语言,还会包括很多其他知识,比如计算机基础知识(数据结构、计算机网络、操作系统等)、C语言基础、Java底层知识以及一些框架相关知识等。本文几乎覆盖到了所有领域。计算机基础知识C语言基础Java基础Java高级Java Web设计模式知识的综合能力工具使用项目相关技术热情表达能力思考方式其他推荐阅读还有,我知道很多人会问关于这些题目的答案问题。答案我都有,由于篇幅有限没办法直接贴上来。这些题目的答案我会在我的公众号及知识星球中给出,感谢关注。为了方便,我把他们分了类,有一些是必看的,我用!标注,有一些进阶型的我用%标注,有一些需要了解的,我用?标注。必会关键字void byte int long char short float double String StringBuffer StringBuilder Array Collection Collections List ArrayList LinkedList Vector Set HashMap TreeMap LinkedHashMap ConcerrentHashMap Set TreeMap HashMap synchronized volatile transient implements extends public private protected this super static final const run start thread enmu stack queue list heap throw throws try catch finally break continue instanceof计算机基础知识数据结构!1、什么是队列、栈、链表!2、什么是树(平衡树,排序树,B树,B+树,R树,红黑树)、堆(大根堆、小根堆)、图(有向图、无向图、拓扑)!3、栈和队列的相同和不同之处?4、栈通常采用的两种存储结构%5、两个栈实现队列,和两个队列实现栈算法!1、排序都有哪几种方法?!2、会写常用的排序算法,如快排,归并等。%3、各种排序算法的时间复杂度和稳定性 ,重点快排。!4、单链表的遍历和逆序!5、深度优先搜索和广度优先搜索?6、最小生成树!7、常见Hash算法,哈希的原理和代价%8、全排列、贪心算法、KMP算法、hash算法?9、一致性Hash算法操作系统?1、虚拟内存管理?2、换页算法!3、进程间通信?4、进程同步:生产者消费者问题、哲学家就餐问题、读者写者问题!5、死锁的四个必要条件,避免方法!6、Linux的一些基本命令,如ls、tail、chmod等计算机网络!1、tcp,udp区别!2、HTTP请求和响应的全过程!3、HTTP常见响应码:200、301、302、404、500!4、get和post的区别!5、forward和redirect的区别!6、osi七层模型!7、tcp/ip四层模型及原理!8、TCP和UDP区别!9、TCP的三次握手,四次关闭%10、丢包,粘包,?11、容量控制,拥塞控制?12、子网划分%13、IPV4和IPV6?14、HTTPS和HTTP/2数据库:!1、范式!2、数据库事务和隔离级别!3、为什么需要锁,锁定分类,锁粒度%4、乐观锁,悲观锁的概念及实现方式!5、分页如何实现(Oracle,MySql)!6、Mysql引擎?7、MYSQL语句优化%8、从一张大表读取数据,如何解决性能问题!9、内连接,左连接,右连接作用及区别!10、Statement和PreparedStatement之间的区别%11、索引以及索引的实现(B+树介绍、和B树、R树区别?12、什么是数据库连接池海量数据处理%1、海量日志数据,如何提取出某日访问淘宝次数最多的IP%2、上亿数据,统计其中出现次数最多的前N个数据%3、5亿个int,找出他们的中位数%4、两个文件,各存放50亿条URL,每个URL占64字节。内存限制是4G,找出两个文件中相同的URL%5、有40亿个不重复的unsigned int的整数,没排过序,现在给一个数,如何快速判断这个数是否在这40亿个数当中。?6、提示:分治、Hash映射、堆排序、双层桶划分、Bloom filter、bitmap、数据库索引、mapreduceC语言基础构造函数、析构函数!1、构造函数和析构函数%2、为什么不要在构造器中调用虚函数%3、为什么不要在析构函数中抛出异常c++相关!1、面向对象的三大基本特征,五大基本原则%2、C++继承的内存布局!3、C++多态的实现机制!4、new/deletr和malloc/free的区别其他!1、为什么使用补码%2、C语言中的内存泄漏!3、进制转换% 4、自己编写strlen/strcpy/strcmp! 5、C、C++以及Java之间的区别和各自优缺点Java基础封装、继承、多态!1、Java中实现多态的机制是什么,动态多态和静态多态的区别!2、接口和抽象类的区别,如何选择!3、Java能不能多继承,可不可以多实现%4、Static Nested Class 和 Inner Class的不同!5、重载和重写的区别。!6、是否可以继承String类!7、构造器是否可被override?!8、public,protected,private的区别?集合相关!1、列举几个Java中Collection类库中的常用类!2、List、Set、Map是否都继承自Collection接口?存储特点分别是什么?!3、ArrayList、LinkedList和Vector之间的区别与联系!4、HashMap和Hashtable、TreeMap以及ConcurrentHashMap的区别!5、Collection 和 Collections的区别%6、其他的集合类:treeset,linkedhashmap等。异常相关!1、Error和Exception的区别!2、异常的类型,什么是运行时异常!3、final、finally和finalize的区别%4、try-catch-finally中,如果在catch中return了,finally中的代码还会执行么,原理是什么?!5、列举3个以上的RuntimeException!6、Java中的异常处理机制的简单原理和应用其它!1、String和StringBuffer、StringBuilder的区别!2、==和equals的区别%3、hashCode的作用,和equals方法的关系!4、Input/OutputStream和Reader/Writer有什么区别!5、如何在字符流和字节流之间转换?!6、switch可以使用那些数据类型%7、Java的四种引用!8、序列化与反序列化!9、正则表达式!10、int和Integer的区别,什么是自动装箱和自动拆箱Java高级多线程!1、进程和线程的区别!2、并行和并发的区别和联系!3、同步与异步!4、多线程的实现方式,有什么区别!5、什么叫守护线程%6、如何停止一个线程?!7、什么是线程安全?!8、synchronized 和 lock的区别!9、当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?!10、启动一个线程是用run()还是start()?!12、wait和sleep的区别%13、notify和notifyAll的区别%14、线程池的作用%15、Java中线程池相关的类JVM底层技术!1、gc的概念,如果A和B对象循环引用,是否可以被GC?%2、jvm gc如何判断对象是否需要回收,有哪几种方式?!3、Java中能不能主动触发GC!4、JVM的内存结构,堆和栈的区别!5、JVM堆的分代%6、Java中的内存溢出是什么,和内存泄露有什么关系!7、Java的类加载机制,什么是双亲委派!8、ClassLoader的类加载方式IO! 1、NIO、AIO和BIO 之间的区别?2、IO和NIO常用用法其它?1、hashcode 有哪些算法!2、反射的基本概念,反射是否可以调用私有方法!3、Java中范型的概念?4、JVM启动参数,-Xms和 -Xmx%5、代理机制的实现!6、String s = new String("s"),创建了几个对象。Java WebServlet!1、JSP和Servlet的区别,Servelt的概念。!2、Servlet的生命周期!3、Servlet中的session工作原理 ,以及设置过期时间的方式!4、Servlet中,filter的应用场景有哪些??5、JSP的动态include和静态include%6、web.xml中常用配置及作用%7、Servlet的线程安全问题MVC框架!1、介绍几个常用的MVC框架!2、什么是MVC!3、Struts中请求的实现过程%4、Spring mvc与Struts mvc的区别?5、Service嵌套事务处理,如何回滚!6、struts2 中拦截器与过滤器的区别及执行顺序%7、struts2拦截器的实现原理http相关!1、session和cookie的区别!2、HTTP请求中session实现原理?%3、如果客户端禁止Cookie能实现Session吗?!4、http中 get和post区别!5、redirect与forward的区别!6、常见的web请求返回的状态码。404、302、301、500分别代表什么SSH相关?1、Hibernate/Ibatis/MyBatis之间的区别?2、什么是OR Mapping%3、hibernate的缓存机制、一级和二级缓存!4、使用Spring的好处是什么,Spring的核心理念!5、什么是AOP和IOC,实现原理是什么!6、spring bean的初始化过程!7、Spring的事务管理 ,Spring bean注入的几种方式%8、spring四种依赖注入方式容器相关!1、什么是web服务器、什么是应用服务器!2、常用的web服务器有哪些??3、Tomcat和weblogic的区别web安全!1、什么是SQL注入 ,如何避免。%2、什么是XSS攻击,如何避免%3、什么是CSRF攻击,如何避免动态代理!1、Java的动态代理的概念%2、Java的动态代理的实现编码问题!1、常用的字符编码!2、如何解决中文乱码问题其它%1、XML的解析方式,以及优缺点。%2、什么是ajax,Ajax如何解决跨域问题设计模式%1、谈一下自己了解或者熟悉的设计模式!2、Singleton的几种实现方式,实现一个线程安全的单例。?3、工厂模式和抽象工厂模式之间的区别知识的综合能力!1、请介绍一下一个http请求的全过程,描述的越全面越好!2、当你在浏览器地址栏输入www.taobao.com,敲下回车之后都发生了什么工具使用!1、知道git/svn是干什么的吗?用过吗!2、知道maven/gradle是干什么的吗?用过吗!3、平常使用什么IDE,为什么!4、平常使用什么浏览器,为什么!5、平常开发机器是什么操作系统的!6、会在Linux上开发吗。Linux常用命令会吗项目相关!1、请简单介绍一下你的这个项目!2、你在这个项目中充当什么角色!3、这个项目的技术选型有做过么。!4、选择某项技术做过哪些调研和对比!5、这个项目中遇到的最大的问题是什么?你是如何解决的。!6、项目中是否考虑过性能、安全性等问题技术热情!1、当前Java的最新版本!2、Java8的lambda表达式%3、Java8的stream API%4、Java9的模块化%5、Java10的局部变量类型推断%6、Spring Boot2.0%7、HTTP/2%8、会FQ么,知道FQ的原理吗!9、你最近在读什么书表达能力!1、能不能简单做一个自我介绍。!2、能不能描述一下杭州给你的印象。用三句话概括一下。思考方式!1、如何估算杭州有多少软件工程师!2、你最近读过的印象最深的文章是什么!3、这篇文章中有几个观点,你最赞成哪一个,最不赞成哪一个其
List和Set比较,各自的子类比较 对比一:Arraylist与LinkedList的比较1、ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。2、因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。   3、LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。4、因为LinkedList要移动指针,所以查询操作性能比较低。 适用场景分析:当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。 对比二:ArrayList与Vector的比较1、Vector的方法都是同步的,是线程安全的,而ArrayList的方法不是,由于线程的同步必然要影响性能。因此,ArrayList的性能比Vector好。 2、当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样。ArrayList就有利于节约内存空间。3、大多数情况不使用Vector,因为性能不好,但是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性。4、Vector可以设置增长因子,而ArrayList不可以。 适用场景分析:1、Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。2、如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。 对比三:HashSet与TreeSet的比较 1.TreeSet 是二叉树实现的,Treeset中的数据是自动排好序的,不允许放入null值 。2.HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束 。3.HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例。 适用场景分析:HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。  HashMap和ConcurrentHashMap的区别1、HashMap不是线程安全的,而ConcurrentHashMap是线程安全的。2、ConcurrentHashMap采用锁分段技术,将整个Hash桶进行了分段segment,也就是将这个大的数组分成了几个小的片段segment,而且每个小的片段segment上面都有锁存在,那么在插入元素的时候就需要先找到应该插入到哪一个片段segment,然后再在这个片段上面进行插入,而且这里还需要获取segment锁。3、ConcurrentHashMap让锁的粒度更精细一些,并发性能更好。 至于两者的底层实现,你如果想通过一篇文章就理解了,那就too young了,好好找些博文+看源码去吧。  HashTable和ConcurrentHashMap的区别它们都可以用于多线程的环境,但是当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。因为ConcurrentHashMap引入了分割(segmentation),不论它变得多么大,仅仅需要锁定map的某个部分,而其它的线程不需要等到迭代完成才能访问map。简而言之,在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。  String,StringBuffer和StringBuilder的区别1、运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String。2、线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的。 适用场景分析:String:适用于少量的字符串操作的情况StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况  wait和sleep的区别1、sleep()方法是属于Thread类中的,而wait()方法,则是属于Object类中的。2、sleep()方法导致了程序暂停执行指定的时间,让出cpu给其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态。所以在调用sleep()方法的过程中,线程不会释放对象锁。3、调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。   JVM的内存结构根据 JVM 规范,JVM 内存共分为虚拟机栈、堆、方法区、程序计数器、本地方法栈五个部分。 1、Java虚拟机栈:线程私有;每个方法在执行的时候会创建一个栈帧,存储了局部变量表,操作数栈,动态连接,方法返回地址等;每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。 2、堆:线程共享;被所有线程共享的一块内存区域,在虚拟机启动时创建,用于存放对象实例。 3、方法区:线程共享;被所有线程共享的一块内存区域;用于存储已被虚拟机加载的类信息,常量,静态变量等。 4、程序计数器:线程私有;是当前线程所执行的字节码的行号指示器,每条线程都要有一个独立的程序计数器,这类内存也称为“线程私有”的内存。 5、本地方法栈:线程私有;主要为虚拟机使用到的Native方法服务。  强引用,软引用和弱引用的区别强引用:只有这个引用被释放之后,对象才会被释放掉,只要引用存在,垃圾回收器永远不会回收,这是最常见的New出来的对象。 软引用:内存溢出之前通过代码回收的引用。软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。 弱引用:第二次垃圾回收时回收的引用,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记。  数组在内存中如何分配1、简单的值类型的数组,每个数组成员是一个引用(指针),引用到栈上的空间(因为值类型变量的内存分配在栈上)2、引用类型,类类型的数组,每个数组成员仍是一个引用(指针),引用到堆上的空间(因为类的实例的内存分配在堆上)  springmvc的核心是什么,请求的流程是怎么处理的,控制反转怎么实现的核心:控制反转和面向切面 请求处理流程:1、首先用户发送请求到前端控制器,前端控制器根据请求信息(如URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的控制逻辑部分;2、页面控制器接收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,并进行验证,然后将命令对象委托给业务对象进行处理;处理完毕后返回一个ModelAndView(模型数据和逻辑视图名);3、前端控制器收回控制权,然后根据返回的逻辑视图名,选择相应的视图进行渲染,并把模型数据传入以便视图渲染;4、前端控制器再次收回控制权,将响应返回给用户。 控制反转如何实现:我们每次使用spring框架都要配置xml文件,这个xml配置了bean的id和class。spring中默认的bean为单实例模式,通过bean的class引用反射机制可以创建这个实例。因此,spring框架通过反射替我们创建好了实例并且替我们维护他们。A需要引用B类,spring框架就会通过xml把B实例的引用传给了A的成员变量。  mybatis如何处理结果集MyBatis的结果集是通过反射来实现的。并不是通过get/set方法。在实体类中无论是否定义get/set()方法,都是可以接收到的。 如果面试只是考你这个点的话就恭喜了。如果继续深问流程,那就需要自己找一些源码来阅读了。  java的多态表现在哪里主要有两种表现形式:重载和重写 重载:是发生在同一类中,具有相同的方法名,主要是看参数的个数,类型,顺序不同实现方法的重载的,返回值的类型可以不同。 重写:是发生在两个类中(父类和子类),具有相同的方法名,主要看方法中参数,个数,类型必须相同,返回值的类型必须相同。  接口有什么用1、通过接口可以实现不相关类的相同行为,而不需要了解对象所对应的类。2、通过接口可以指明多个类需要实现的方法。3、通过接口可以了解对象的交互界面,而不需了解对象所对应的类。另:Java是单继承,接口可以使其实现多继承的功能。  说说http,https协议 HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。 HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。 区别:1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。  说说tcp/ip协议族TCP/IP协议族是一个四层协议系统,自底而上分别是数据链路层、网络层、传输层和应用层。每一层完成不同的功能,且通过若干协议来实现,上层协议使用下层协议提供的服务。1、数据链路层负责帧数据的传递。2、网络层责数据怎样传递过去。3、传输层负责传输数据的控制(准确性、安全性)4、应用层负责数据的展示和获取。  tcp五层网络协议物理层:为数据端设备提供传送数据的通路,数据通路可以是一个物理媒体,也可以是多个物理媒体连接而成。 数据链路层:为网络层提供数据传送服务。 网络层:路由选择和中继、激活,终止网络连接、在一条数据链路上复用多条网络连接,多采取分时复用技术 、差错检测与恢复、排序,流量控制、服务选择、网络管理 。 传输层:传输层是两台计算机经过网络进行数据通信时,第一个端到端的层次,具有缓冲作用。 应用层:应用层向应用程序提供服务  TCP与UDP的区别1、基于连接与无连接2、TCP要求系统资源较多,UDP较少; 3、UDP程序结构较简单 4、流模式(TCP)与数据报模式(UDP); 5、TCP保证数据正确性,UDP可能丢包 6、TCP保证数据顺序,UDP不保证   cookie和session的区别,分布式环境怎么保存用户状态1、cookie数据存放在客户的浏览器上,session数据放在服务器上。2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用COOKIE。4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。 分布式环境下的session(举例两种): 服务器session复制原理:任何一个服务器上的session发生改变(增删改),该节点会把这个 session的所有内容序列化,然后广播给所有其它节点,不管
这个主题的内容之前分三个篇幅分享过,导致网络上传播的比较分散,所以本篇做了一个汇总,同时对部分内容及答案做了修改,欢迎朋友们吐槽、转发。因为篇幅长度和时间的原因,部分答案我没有亲自总结。更多精彩内容请关注我的微信公众号:Java团长1.面向对象和面向过程的区别面向过程优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。缺点:没有面向对象易维护、易复用、易扩展面向对象优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护缺点:性能比面向过程低2.Java的四个基本特性(抽象、封装、继承,多态)抽象:就是把现实生活中的某一类东西提取出来,用程序代码表示,我们通常叫做类或者接口。抽象包括两个方面:一个是数据抽象,一个是过程抽象。数据抽象也就是对象的属性。过程抽象是对象的行为特征。封装:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行封装隐藏。封装分为属性的封装和方法的封装。继承:是对有着共同特性的多类事物,进行再抽象成一个类。这个类就是多类事物的父类。父类的意义在于抽取多类事物的共性。多态:允许不同类的对象对同一消息做出响应。方法的重载、类的覆盖正体现了多态。3.重载和重写的区别重载:发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类;如果父类方法访问修饰符为private则子类中就不是重写。4.构造器Constructor是否可被override构造器不能被重写,不能用static修饰构造器,只能用publicprivate protected这三个权限修饰符,且不能有返回语句。5.访问控制符public,protected,private,以及默认的区别private只有在本类中才能访问;public在任何地方都能访问;protected在同包内的类及包外的子类能访问;默认不写在同包内能访问。6是否可以继承String类#String类是final类故不可以继承,一切由final修饰过的都不能继承。7.String和StringBuffer、StringBuilder的区别#可变性String类中使用字符数组保存字符串,privatefinal char value[],所以string对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[]value,这两种对象都是可变的。线程安全性String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。性能每次对String 类型进行改变的时候,都会生成一个新的String 对象,然后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。8.hashCode和equals方法的关系#equals相等,hashcode必相等;hashcode相等,equals可能不相等。9.抽象类和接口的区别#语法层次抽象类和接口分别给出了不同的语法定义。设计层次抽象层次不同,抽象类是对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。抽象类是自底向上抽象而来的,接口是自顶向下设计出来的。跨域不同抽象类所体现的是一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is-a"关系,即父类和派生类在概念本质上应该是相同的。对于接口则不然,并不要求接口的实现者和接口定义在概念本质上是一致的,仅仅是实现了接口定义的契约而已,"like-a"的关系。10.自动装箱与拆箱#装箱:将基本类型用它们对应的引用类型包装起来;拆箱:将包装类型转换为基本数据类型;Java使用自动装箱和拆箱机制,节省了常用数值的内存开销和创建对象的开销,提高了效率,由编译器来完成,编译器会在编译期根据语法决定是否进行装箱和拆箱动作。11.什么是泛型、为什么要使用以及泛型擦除#泛型,即“参数化类型”。创建集合时就指定集合元素的类型,该集合只能保存其指定类型的元素,避免使用强制类型转换。Java编译器生成的字节码是不包涵泛型信息的,泛型类型信息将在编译处理是被擦除,这个过程即类型擦除。泛型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。类型擦除的主要过程如下:1).将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。2).移除所有的类型参数。12.Java中的集合类及关系图#List和Set继承自Collection接口。Set无序不允许元素重复。HashSet和TreeSet是两个主要的实现类。List有序且允许元素重复。ArrayList、LinkedList和Vector是三个主要的实现类。Map也属于集合系统,但和Collection接口没关系。Map是key对value的映射集合,其中key列就是一个集合。key不能重复,但是value可以重复。HashMap、TreeMap和Hashtable是三个主要的实现类。SortedSet和SortedMap接口对元素按指定规则排序,SortedMap是对key列进行排序。13.HashMap实现原理#具体原理参考文章:http://zhangshixi.iteye.com/blog/672697http://www.admin10000.com/document/3322.html14.HashTable实现原理#具体原理参考文章:http://www.cnblogs.com/skywang12345/p/3310887.htmlhttp://blog.csdn.net/chdjj/article/details/3858103515.HashMap和HashTable区别#1).HashTable的方法前面都有synchronized来同步,是线程安全的;HashMap未经同步,是非线程安全的。2).HashTable不允许null值(key和value都不可以) ;HashMap允许null值(key和value都可以)。3).HashTable有一个contains(Objectvalue)功能和containsValue(Objectvalue)功能一样。4).HashTable使用Enumeration进行遍历;HashMap使用Iterator进行遍历。5).HashTable中hash数组默认大小是11,增加的方式是old*2+1;HashMap中hash数组的默认大小是16,而且一定是2的指数。6).哈希值的使用不同,HashTable直接使用对象的hashCode; HashMap重新计算hash值,而且用与代替求模。16.ArrayList和vector区别#ArrayList和Vector都实现了List接口,都是通过数组实现的。Vector是线程安全的,而ArrayList是非线程安全的。List第一次创建的时候,会有一个初始大小,随着不断向List中增加元素,当List 认为容量不够的时候就会进行扩容。Vector缺省情况下自动增长原来一倍的数组长度,ArrayList增长原来的50%。17.ArrayList和LinkedList区别及使用场景#区别ArrayList底层是用数组实现的,可以认为ArrayList是一个可改变大小的数组。随着越来越多的元素被添加到ArrayList中,其规模是动态增加的。LinkedList底层是通过双向链表实现的, LinkedList和ArrayList相比,增删的速度较快。但是查询和修改值的速度较慢。同时,LinkedList还实现了Queue接口,所以他还提供了offer(),peek(), poll()等方法。使用场景LinkedList更适合从中间插入或者删除(链表的特性)。ArrayList更适合检索和在末尾插入或删除(数组的特性)。18.Collection和Collections的区别#java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。19.Concurrenthashmap实现原理#具体原理参考文章:http://www.cnblogs.com/ITtangtang/p/3948786.htmlhttp://ifeve.com/concurrenthashmap/20.Error、Exception区别#Error类和Exception类的父类都是throwable类,他们的区别是:Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。Exception类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。21.UncheckedException和Checked Exception,各列举几个#Unchecked Exception:a. 指的是程序的瑕疵或逻辑错误,并且在运行时无法恢复。b. 包括Error与RuntimeException及其子类,如:OutOfMemoryError,UndeclaredThrowableException, IllegalArgumentException,IllegalMonitorStateException, NullPointerException, IllegalStateException,IndexOutOfBoundsException等。c. 语法上不需要声明抛出异常。Checked Exception:a. 代表程序不能直接控制的无效外界情况(如用户输入,数据库问题,网络异常,文件丢失等)b. 除了Error和RuntimeException及其子类之外,如:ClassNotFoundException,NamingException, ServletException, SQLException, IOException等。c. 需要try catch处理或throws声明抛出异常。22.Java中如何实现代理机制(JDK、CGLIB)#JDK动态代理:代理类和目标类实现了共同的接口,用到InvocationHandler接口。CGLIB动态代理:代理类是目标类的子类,用到MethodInterceptor接口。23.多线程的实现方式#继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。24.线程
最近看到网上流传着各种面试经验及面试题,往往都是一大堆技术题目贴上去,但是没有答案。为此我业余时间整理了40道Java基础常见的面试题及详细答案,望各路大牛发现不对的地方不吝赐教,留言即可。八种基本数据类型的大小,以及他们的封装类引用数据类型Switch能否用string做参数equals与==的区别自动装箱,常量池Object有哪些公用方法Java的四种引用,强弱软虚,用到的场景Hashcode的作用HashMap的hashcode的作用为什么重载hashCode方法?ArrayList、LinkedList、Vector的区别String、StringBuffer与StringBuilder的区别Map、Set、List、Queue、Stack的特点与用法HashMap和HashTable的区别JDK7与JDK8中HashMap的实现HashMap和ConcurrentHashMap的区别,HashMap的底层源码ConcurrentHashMap能完全替代HashTable吗为什么HashMap是线程不安全的如何线程安全的使用HashMap多并发情况下HashMap是否还会产生死循环TreeMap、HashMap、LindedHashMap的区别Collection包结构,与Collections的区别try?catch?finally,try里有return,finally还执行么Excption与Error包结构,OOM你遇到过哪些情况,SOF你遇到过哪些情况Java(OOP)面向对象的三个特征与含义Override和Overload的含义去区别Interface与abstract类的区别Static?class?与non?static?class的区别java多态的实现原理foreach与正常for循环效率对比Java?IO与NIOjava反射的作用于原理泛型常用特点解析XML的几种方式的原理与特点:DOM、SAXJava1.7与1.8,1.9,10 新特性设计模式:单例、工厂、适配器、责任链、观察者等等JNI的使用AOP是什么OOP是什么AOP与OOP的区别八种基本数据类型的大小,以及他们的封装类八种基本数据类型:int、short、float、double、long、boolean、byte、char。封装类分别是:Integer、Short、Float、Double、Long、Boolean、Byte、Character。引用数据类型引用数据类型是由类的编辑器定义的,他们是用于访问对象的。这些变量被定义为不可更改的特定类型。例如:Employee, Puppy 等等类对象和数组变量就是这种引用数据类型。任何引用数据类型的默认值都为空。一个引用数据类型可以被用于任何声明类型和兼容类型的对象。Switch能否用string做参数jdk7之前 switch 只能支持 byte、short、char、int 这几个基本数据类型和其对应的封装类型。switch后面的括号里面只能放int类型的值,但由于byte,short,char类型,它们会?自动?转换为int类型(精精度小的向大的转化),所以它们也支持。jdk1.7后 整形,枚举类型,字符串都可以。原理1234567891011switch (expression)  // 括号里是一个表达式,结果是个整数{  case constant1:   // case 后面的标号,也是个整数     group of statements 1;     break;  case constant2:     group of statements 2;     break;  ...  default:     default group of statements}jdk1.7后,整形,枚举类,字符串都可以。1234567891011121314151617public class TestString {     static String string = "123";    public static void main(String[] args) {        switch (string) {        case "123":            System.out.println("123");            break;        case "abc":            System.out.println("abc");            break;        default:            System.out.println("defauls");            break;        }    }}为什么jdk1.7后又可以用string类型作为switch参数呢?其实,jdk1.7并没有新的指令来处理switch string,而是通过调用switch中string.hashCode,将string转换为int从而进行判断。equals与==的区别使用==比较原生类型如:boolean、int、char等等,使用equals()比较对象。1、==是判断两个变量或实例是不是指向同一个内存空间。 equals是判断两个变量或实例所指向的内存空间的值是不是相同。2、==是指对内存地址进行比较。 equals()是对字符串的内容进行比较。3、==指引用是否相同。 equals()指的是值是否相同。12345678910111213141516171819202122public static void main(String[] args) {         String a = new String("ab"); // a 为一个引用        String b = new String("ab"); // b为另一个引用,对象的内容一样        String aa = "ab"; // 放在常量池中        String bb = "ab"; // 从常量池中查找         System.out.println(aa == bb); // true        System.out.println(a == b); // false,非同一对象        System.out.println(a.equals(b)); // true        System.out.println(42 == 42.0);  // true    } public static void main(String[] args) {    Object obj1 = new Object();    Object obj2 = new Object();    System.out.println(obj1.equals(obj2));//false    System.out.println(obj1==obj2);//false    obj1=obj2;    System.out.println(obj1==obj2);//true    System.out.println(obj2==obj1);//true}自动装箱,常量池自动装箱 在jdk?1.5之前,如果你想要定义一个value为100的Integer对象,则需要如下定义:123456Integer i = new Integer(100); int intNum1 = 100; //普通变量Integer intNum2 = intNum1; //自动装箱int intNum3 = intNum2; //自动拆箱Integer intNum4 = 100; //自动装箱上面的代码中,intNum2为一个Integer类型的实例,intNum1为Java中的基础数据类型,将intNum1赋值给intNum2便是自动装箱;而将intNum2赋值给intNum3则是自动拆箱。八种基本数据类型: boolean byte char shrot int long float double ,所生成的变量相当于常量。基本类型包装类:Boolean Byte Character Short Integer Long Float Double。自动拆箱和自动装箱定义:自动装箱是将一个java定义的基本数据类型赋值给相应封装类的变量。 拆箱与装箱是相反的操作,自动拆箱则是将一个封装类的变量赋值给相应基本数据类型的变量。Object有哪些公用方法Object是所有类的父类,任何类都默认继承Objectclone 保护方法,实现对象的浅复制,只有实现了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 转换成字符串,一般子类都有重写,否则打印句柄。Java的四种引用,强弱软虚,用到的场景从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。1、强引用最普遍的一种引用方式,如String s = "abc",变量s就是字符串“abc”的强引用,只要强引用存在,则垃圾回收器就不会回收这个对象。2、软引用(SoftReference)用于描述还有用但非必须的对象,如果内存足够,不回收,如果内存不足,则回收。一般用于实现内存敏感的高速缓存,软引用可以和引用队列ReferenceQueue联合使用,如果软引用的对象被垃圾回收,JVM就会把这个软引用加入到与之关联的引用队列中。3、弱引用(WeakReference)弱引用和软引用大致相同,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。4、虚引用(PhantomReference)就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。 虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。Hashcode的作用http://blog.csdn.net/seu_calvin/article/details/520941151、HashCode的特性(1)HashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,HashCode经常用于确定对象的存储地址。(2)如果两个对象相同,?equals方法一定
一、面试题基础总结1、 JVM结构原理、GC工作机制详解答:具体参照:JVM结构、GC工作机制详解     ,说到GC,记住两点:1、GC是负责回收所有无任何引用对象的内存空间。 注意:垃圾回收回收的是无任何引用的对象占据的内存空间而不是对象本身,2、GC回收机制的两种算法,a、引用计数法  b、可达性分析算法(  这里的可达性,大家可以看基础2 Java对象的什么周期),至于更详细的GC算法介绍,大家可以参考:Java GC机制算法2、Java对象的生命周期答:创建阶段 、 应用阶段 、不可见阶段 、不可达阶段 、收集阶段 、终结阶段、 对象空间重新分配阶段等等,具体参照:Java 对象的生命周期3、Map或者HashMap的存储原理答:HashMap是由数组+链表的一个结构组成,具体参照:HashMap的实现原理4、当数据表中A、B字段做了组合索引,那么单独使用A或单独使用B会有索引效果吗?(使用like查询如何有索引效果)答:看A、B两字段做组合索引的时候,谁在前面,谁在后面,如果A在前,那么单独使用A会有索引效果,单独使用B则没有,反之亦然。同理,使用like模糊查询时,如果只是使用前面%,那么有索引效果,如果使用双%号匹配,那么则无索引效果5、数据库存储日期格式时,如何考虑时区转换问题?答:使用TimeStamp ,  原因参照:Java编程中遇到的时区转换问题6、Java Object类中有哪些方法?答:Object有哪些方法7、HTTP协议,GET和POST 的区别答:浅谈HTTP中GET和POST的区别二、线程、设计模式、缓存方面1、SimpleDataFormat是非线程安全的,如何更好的使用而避免风险呢答:关于SimpleDateFormat安全的时间格式化线程安全问题2、如何看待设计模式,并简单说说你对观察者模式的理解答:1、设计模式有神马用     2、观察者模式类图及实现3、集群环境中,session如何实现共享答:1、Java集群之session共享    2、session多服务器共享方案,还有一种方案就是使用一个固定的服务器专门保持session,其他服务器共享4、分布式、集群环境中,缓存如何刷新,如何保持同步?答:A、缓存如何刷新? 1、定时刷新  2、主动刷新覆盖   ,每个缓存框架都有自带的刷新机制,或者说缓存失效机制,就拿Redis和 Ehcache举例, 他们都有自带的过期机制,另外主动刷新覆盖时,只需获取对应的key进行数据的覆盖即可B、缓存如何保持同步?  这个redis有自带的集群同步机制,即复制功能,具体参考:基于Redis分布式缓存实现      ,Ehcache也有分布式缓存同步的配置,只需要配置不同服务器地址即可,参照:Ehcache分布式缓存同步5、一条sql执行过长的时间,你如何优化,从哪些方面?答:1、查看sql是否涉及多表的联表或者子查询,如果有,看是否能进行业务拆分,相关字段冗余或者合并成临时表(业务和算法的优化)2、涉及链表的查询,是否能进行分表查询,单表查询之后的结果进行字段整合3、如果以上两种都不能操作,非要链表查询,那么考虑对相对应的查询条件做索引。加快查询速度4、针对数量大的表进行历史表分离(如交易流水表)5、数据库主从分离,读写分离,降低读写针对同一表同时的压力,至于主从同步,mysql有自带的binlog实现 主从同步6、explain分析sql语句,查看执行计划,分析索引是否用上,分析扫描行数等等7、查看mysql执行日志,看看是否有其他方面的问题个人理解:从根本上来说,查询慢是占用mysql内存比较多,那么可以从这方面去酌手考虑三、三大框架方面问题1、Spring 事务的隔离性,并说说每个隔离性的区别解答:Spring事务详解2、Spring事务的传播行为,并说说每个传播行为的区别解答:Spring事务详解3、hibernate跟Mybatis/ ibatis 的区别,为什么选择?解答:Hibernate与Mybatis的比较4、Struts跟Spring mvc的优缺点,让你选会如何选解答:Spring MVC 与 Struts的区别5、简单说说Spring 事务机制解答:Spring事务机制6、Spring 4.0新特性解答:Spring4新特性四、负载均衡、集群相关1、weblogic 负载均衡的原理和集群的配置解答:a、WEBLOGIC负载均衡原理    b、负载均衡和集群的配置(参考)2、Nginx+Tomcat+Redis实现负载均衡、资源分离、session共享 解答:配置参考3、nginx配置文件详解——nginx.conf解答:Nginx配置文件详细说明五、项目优化相关1、web如何项目优化解答:这个我整理过一次,web项目性能优化(整理)2、单例模式有几种? 如何优化?解答:单例模式的7中用法3、简单说说线程池的原理和实现解答:线程原理及实现六、并发和安全方面1、项目并发如何处理?(我们是web项目)解答:高并发量网站解决方案,另外,还有数据库乐观锁,数据库读写分离、使用消息队列、多用存储过程等等2、简单说说功能权限存在的水平权限漏洞和垂直权限漏洞的场景和解决办法(因为我们目前权限级别就是功能权限)解答:A、水平权限漏洞,如下图假设机构有 用户A和用户B 两个用户,其中A有1、2和3权限 ,  用户B有 2 和3 的权限,这时候假设用户B 知道1,并给自己添加1的权限,这时候就是水平权限漏洞。目前解决办法:1、限制入口,让用户B无法编辑自己的权限   2、对用户B无法进行向上扩展。最根本的解决办法是深入到数据权限解答:水平权限漏洞和解决办法B、垂直权限漏洞解答:垂直权限漏洞案例和解决方案3、平台上的图片如何防盗链解答:http下载防盗链原理:http协议的字段referer记录来实现4、如何区分上传的图片是不是木马?解答:1、看上传的图片后缀  2、如何后缀是篡改的,那么每个文件有个魔术数字  文件上传-魔术数字5、消息队列的原理和实现解答:1、消息队列原理     2、深入浅出 消息队列 ActiveMQ七、数据库方面1、mysql查询字段区不区分大小写?解答:不区分,哪怕值也不区分(我当时还反问了,区不区分大小的应用含义有哪些,面试官没说得出来)2、简单说说数据库集群和负载均衡、分布式(我不懂这块)解答:数据库负载均衡和集群参考 ,参考23、存储过程的结构和优点解答:大概结构  存储过程的优缺点4、触发器的原理和作用解答:参考八、Java底层基础题1、SpringMVC的原理以及返回数据如何渲染到jsp/html上?答:Spring MVC的核心就是 DispatcherServlet , 一个请求经过 DispatcherServlet ,转发给HandlerMapping ,然后经反射,对应 Controller及其里面方法的@RequestMapping地址,最后经ModelAndView和ViewResoler返回给对应视图  。  具体可参考:Spring MVC的工作原理2、一个类对象属性发生改变时,如何让调用者知道?答:Java event时间监听  ,即在set方法改变属性时,触发 ,这种模式也可以理解为观察者模式,具体查看:观察者模式简单案例和说明3、重写equals为何要重写hashCode?答:判断两个对象是否相等,比较的就是其hashCode, 如果你重载了equals,比如说是基于对象的内容实现的,而保留hashCode的实现不变,那么很可能某两个对象明明是“相等”,而hashCode却不一样。  hashcode不一样,就无法认定两个对象相等了4、谈谈你对JVM的理解?答: Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。Java编译器只要面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。JVM执行程序的过程 :I.加载。class文件   ,II.管理并分配内存  ,III.执行垃圾收集JRE(java运行时环境)由JVM构造的java程序的运行环境  具体详情:JVM原理和调优5、Mysql的事物隔离级别?答:Mysql的事物隔离级别 其实跟 Spring的事物隔离级别一样,都是1、Read Uncommitted(读取未提交内容), 2、Read Committed(读取提交内容),3、Repeatable Read(可重读),4、Serializable(可串行化)    具体参照:mysql事物隔离级别6、Spring的原理答:Spring的核心是IOC和AOP  ,IOC是依赖注入和控制反转, 其注入方式可分为set注入、构造器注入、接口注入等等。IOC就是一个容器,负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。简单理解就是:JAVA每个业务逻辑处理至少需要两个或者以上的对象协作进行工作,但是每个对象在使用它的合作对象的时候,都需要频繁的new 对象来实现,你就会发现,对象间的耦合度高了。而IOC的思想是:Spring容器来管理这些,对象只需要处理本身业务关系就好了。至于什么是控制反转,就是获得依赖对象的方式反转了。AOP呢,面向切面编程,最直接的体现就是Spring事物管理。至于Spring事物的相关资料,就不细说了,参考:Spring注解式事物管理7、谈谈你对NIO的理解答:IO是面向流,NIO是面向缓冲 ,这里不细讲了,具体参照:Java NIO和IO的区别8、ArrayList和LinkedList、Vector的区别?答:总得来说可以理解为:.     1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。      2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。      3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据Vector和ArrayList类似,但属于强同步类,即线程安全的,具体比较参照:比较ArrayList、LinkedList、Vector9、随便说说几个单例模式,并选择一种线程安全的答:单例的类别:懒汉、饿汉、枚举、静态内部类、双重校验锁 等等 , 选择线程安全我选最后一种,双重校验锁。  具体实现方式参照:Java:单例模式的七种写法10、谈谈红黑树答:算法和数据结构一直是我薄弱之处,这方面说自己补吧,成效不大,这里我就推荐一个:红黑树11、举例说说几个排序,并说明其排序原理答:这里我就不细说了,大家自己看看 Java实现几种常见的排序算法12、Mysql索引的原理答:索引的作用大家都知道,就是加快查询速度,但是原理,我说不上来,这里直接看吧:Mysql索引工作原理13、序列化的原理和作用答:Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程,主要用于HTTP或者WebService接口传输过程中对象参数的传播,具体可参看:Java序列化机制和原理九、并发及项目调优1、说说线程安全的几种实现方式?答:什么是线程安全? 我的理解是这样的,一个对象被多个线程同时访问,还能保持其内部属性的顺序性及同步性,则认定为线程安全。实现线程安全的三种方式:被volatile、synchronized等关键字修饰,或者使用java.util.concurrent下面的类库。  至于前两者的关系,参考:synchronized和volatile的用法区别2、方法内部,如何实现更好的异步?答:我们知道异步其实就是让另一个线程去跑,那么如何创建线程?  第一种直接new Thread ,第二种new 一个实现Runnable接口的实现类。 第三种,通过线程池来管理创建等 ,这里说到更好的实现异步,那就是说我们在方法内部避免频繁的new 线程,就可以考虑线程池了。 那么线程池如何创建? 这里可以new 一个线程池,但是需要考虑单例,或者在程序初始启东时,就创建一个线程池,让他跑
简历篇请自我介绍请介绍项目基础篇基本功面向对象的特征final, finally, finalize 的区别int 和 Integer 有什么区别重载和重写的区别抽象类和接口有什么区别说说反射的用途及实现说说自定义注解的场景及实现HTTP 请求的 GET 与 POST 方式的区别session 与 cookie 区别session 分布式处理JDBC 流程MVC 设计思想equals 与 == 的区别集合List 和 Set 区别List 和 Map 区别Arraylist 与 LinkedList 区别ArrayList 与 Vector 区别HashMap 和 Hashtable 的区别HashSet 和 HashMap 区别HashMap 和 ConcurrentHashMap 的区别HashMap 的工作原理及代码实现ConcurrentHashMap 的工作原理及代码实现线程创建线程的方式及实现sleep() 、join()、yield()有什么区别说说 CountDownLatch 原理说说 CyclicBarrier 原理说说 Semaphore 原理说说 Exchanger 原理说说 CountDownLatch 与 CyclicBarrier 区别ThreadLocal 原理分析讲讲线程池的实现原理线程池的几种方式与使用场景线程的生命周期锁机制说说线程安全问题volatile 实现原理synchronize 实现原理synchronized 与 lock 的区别CAS 乐观锁ABA 问题乐观锁的业务场景及实现方式核心篇数据存储MySQL 索引使用的注意事项说说反模式设计说说分库与分表设计分库与分表带来的分布式困境与应对之策说说 SQL 优化之道MySQL 遇到的死锁问题存储引擎的 InnoDB 与 MyISAM数据库索引的原理为什么要用 B-tree聚集索引与非聚集索引的区别limit 20000 加载很慢怎么解决选择合适的分布式主键方案选择合适的数据存储方案ObjectId 规则聊聊 MongoDB 使用场景倒排索引聊聊 ElasticSearch 使用场景缓存使用Redis 有哪些类型Redis 内部结构Redis 内存淘汰机制聊聊 Redis 使用场景Redis 持久化机制Redis 集群方案与实现Redis 为什么是单线程的缓存崩溃缓存降级使用缓存的合理性问题消息队列消息队列的使用场景消息的重发补偿解决思路消息的幂等性解决思路(已解答,待补充)消息的堆积解决思路自己如何实现消息队列如何保证消息的有序性框架篇SpringBeanFactory 和 ApplicationContext 有什么区别Spring Bean 的生命周期Spring IOC 如何实现说说 Spring AOPSpring AOP 实现原理动态代理(cglib 与 JDK)Spring 事务实现方式Spring 事务底层原理如何自定义注解实现功能Spring MVC 运行流程Spring MVC 启动流程Spring 的单例实现原理Spring 框架中用到了哪些设计模式Spring 其他产品(Srping Boot、Spring Cloud、Spring Secuirity、Spring Data、Spring AMQP 等)Netty为什么选择 Netty说说业务中,Netty 的使用场景原生的 NIO 在 JDK 1.7 版本存在 epoll bug什么是TCP 粘包/拆包TCP粘包/拆包的解决办法Netty 线程模型说说 Netty 的零拷贝Netty 内部执行流程Netty 重连实现微服务篇微服务前后端分离是如何做的如何解决跨域微服务哪些框架你怎么理解 RPC 框架说说 RPC 的实现原理说说 Dubbo 的实现原理你怎么理解 RESTful说说如何设计一个良好的 API如何理解 RESTful API 的幂等性如何保证接口的幂等性说说 CAP 定理、 BASE 理论怎么考虑数据一致性问题说说最终一致性的实现方案你怎么看待微服务微服务与 SOA 的区别如何拆分服务微服务如何进行数据库管理如何应对微服务的链式调用异常对于快速追踪与定位问题微服务的安全分布式谈谈业务中使用分布式的场景Session 分布式方案分布式锁的场景分布是锁的实现方案分布式事务集群与负载均衡的算法与实现说说分库与分表设计分库与分表带来的分布式困境与应对之策安全问题安全要素与 STRIDE 威胁防范常见的 Web 攻击服务端通信安全攻防HTTPS 原理剖析HTTPS 降级攻击授权与认证基于角色的访问控制基于数据的访问控制性能优化性能指标有哪些如何发现性能瓶颈性能调优的常见手段说说你在项目中如何进行性能调优工程篇需求分析你如何对需求原型进行理解和拆分说说你对功能性需求的理解说说你对非功能性需求的理解你针对产品提出哪些交互和改进意见你如何理解用户痛点设计能力说说你在项目中使用过的 UML 图你如何考虑组件化你如何考虑服务化你如何进行领域建模你如何划分领域边界说说你项目中的领域建模说说概要设计设计模式你项目中有使用哪些设计模式说说常用开源框架中设计模式使用分析说说你对设计原则的理解23种设计模式的设计理念设计模式之间的异同,例如策略模式与状态模式的区别设计模式之间的结合,例如策略模式+简单工厂模式的实践设计模式的性能,例如单例模式哪种性能更好。业务工程你系统中的前后端分离是如何做的说说你的开发流程你和团队是如何沟通的你如何进行代码评审说说你对技术与业务的理解说说你在项目中经常遇到的 Exception说说你在项目中遇到感觉最难Bug,怎么解决的说说你在项目中遇到印象最深困难,怎么解决的你觉得你们项目还有哪些不足的地方你是否遇到过 CPU 100% ,如何排查与解决你是否遇到过 内存 OOM ,如何排查与解决说说你对敏捷开发的实践说说你对开发运维的实践介绍下工作中的一个对自己最有价值的项目,以及在这个过程中的角色软实力说说你的亮点说说你最近在看什么书说说你觉得最有意义的技术书籍说说个人发展方向方面的思考说说你认为的服务端开发工程师应该具备哪些能力说说你认为的架构师是什么样的,架构师主要做什么说说你所理解的技术专家HR 篇你为什么离开之前的公司你为什么要进我们公司说说职业规划你如何看待加班问题谈一谈你的一次失败经历你觉得你最大的优点是什么你觉得你最大的缺点是什么你在工作之余做什么事情你为什么认为你适合这个职位你觉得自己那方面能力最急需提高你来我们公司最希望得到什么你希望从这份工作中获得什么你对现在应聘的职位有什么了解您还有什么想问的你怎么看待自己的职涯谈谈你的家庭情况你有什么业余爱好你计划在公司工作多久我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
前言16年毕业到现在也近两年了,最近面试了阿里集团(菜鸟网络,蚂蚁金服),网易,滴滴,点我达,最终收到点我达,网易offer,蚂蚁金服二面挂掉,菜鸟网络一个月了还在流程中...最终有幸去了网易。但是要特别感谢点我达的领导及HR,真的非常非常好,很感谢他们一直的关照和指导。面试整体事项简历要准备好,联系方式一定要正确清晰醒目,项目经历按照时间倒序阐述,注意描述自己在项目中承担的职责,简历的模板尽量选择简洁的,毕竟程序员大部分还是喜欢简单明了的。推荐boss直聘,我觉得很好用(不是广告)。一般的整体面试流程都是电面->现场面->HR面->等着。不要觉得HR说让你回去等消息就是GG了,他们也要跟你之前的面试官讨论,再向领导汇报,如果说不急可能还要和其他候选人比较,所以HR让你回去等消息绝对不是说明你完蛋了。面试前准备好自我介绍,1分钟左右就可以,可以写在纸上,电面可以照着念,等你到了现场面了基本也都快背下来你的自我介绍了。准备好扎实的基础,这是一切的根源,没实力怎么都没用的。面试中你可以把你的面试官往你会的知识上引导(我遇到过你会什么他不问什么的)。遇到了设计类题目不要着急,面试官不是为了让你几分钟设计一个高并发高可用设计模式完美的架构,只是想看看你的思路,看看你应变的能力,然后给你些提示看看你能否迅速的调整。offer都会有的,不要着急,把面试当成一个交流的过程。需要准备的知识以下为在近期面试中比较有印象的问题,也就不分公司了,因为没什么意义,大致分类记录一下,目前只想起这么多,不过一定要知道这些问题只是冰山一角,就算都会了也不能怎么样,最最重要的,还是坚实的基础,清醒的头脑。Java基础HashMap的源码,实现原理,JDK8中对HashMap做了怎样的优化。HaspMap扩容是怎样扩容的,为什么都是2的N次幂的大小。HashMap,HashTable,ConcurrentHashMap的区别。极高并发下HashTable和ConcurrentHashMap哪个性能更好,为什么,如何实现的。HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么。java中四种修饰符的限制范围。Object类中的方法。接口和抽象类的区别,注意JDK8的接口可以有实现。动态代理的两种方式,以及区别。Java序列化的方式。传值和传引用的区别,Java是怎么样的,有没有传值引用。一个ArrayList在循环过程中删除,会不会出问题,为什么。@transactional注解在什么情况下会失效,为什么。数据结构和算法B+树快速排序,堆排序,插入排序(其实八大排序算法都应该了解一致性Hash算法,一致性Hash算法的应用JVMJVM的内存结构。JVM方法栈的工作过程,方法栈和本地方法栈有什么区别。JVM的栈中引用如何和堆中的对象产生关联。可以了解一下逃逸分析技术。GC的常见算法,CMS以及G1的垃圾回收过程,CMS的各个阶段哪两个是Stop the world的,CMS会不会产生碎片,G1的优势。标记清除和标记整理算法的理解以及优缺点。eden survivor区的比例,为什么是这个比例,eden survivor的工作过程。JVM如何判断一个对象是否该被GC,可以视为root的都有哪几种类型。强软弱虚引用的区别以及GC对他们执行怎样的操作。Java是否可以GC直接内存。Java类加载的过程。双亲委派模型的过程以及优势。常用的JVM调优参数。dump文件的分析。Java有没有主动触发GC的方式(没有)。多线程Java实现多线程有哪几种方式。Callable和Future的了解。线程池的参数有哪些,在线程池创建一个线程的过程。volitile关键字的作用,原理。synchronized关键字的用法,优缺点。Lock接口有哪些实现类,使用场景是什么。可重入锁的用处及实现原理,写时复制的过程,读写锁,分段锁(ConcurrentHashMap中的segment)。悲观锁,乐观锁,优缺点,CAS有什么缺陷,该如何解决。ABC三个线程如何保证顺序执行。线程的状态都有哪些。sleep和wait的区别。notify和notifyall的区别。ThreadLocal的了解,实现原理。数据库相关常见的数据库优化手段索引的优缺点,什么字段上建立索引数据库连接池。durid的常用配置。计算机网络TCP,UDP区别。三次握手,四次挥手,为什么要四次挥手。长连接和短连接。连接池适合长连接还是短连接。设计模式观察者模式代理模式单例模式,有五种写法,可以参考文章单例模式的五种实现方式可以考Spring中使用了哪些设计模式分布式相关分布式事务的控制。分布式锁如何设计。分布式session如何设计。dubbo的组件有哪些,各有什么作用。zookeeper的负载均衡算法有哪些。dubbo是如何利用接口就可以通信的。缓存相关redis和memcached的区别。redis支持哪些数据结构。redis是单线程的么,所有的工作都是单线程么。redis如何存储一个String的。redis的部署方式,主从,集群。redis的哨兵模式,一个key值如何在redis集群中找到存储在哪里。redis持久化策略。框架相关SpringMVC的Controller是如何将参数和前端传来的数据一一对应的。Mybatis如何找到指定的Mapper的,如何完成查询的。Quartz是如何完成定时任务的。自定义注解的实现。Spring使用了哪些设计模式。Spring的IOC有什么优势。Spring如何维护它拥有的bean。一些较新的东西JDK8的新特性,流的概念及优势,为什么有这种优势。区块链了解如何设计双11交易总额面板,要做到高并发高可用。一些小建议可以去leetcode上刷题换换思路。八大排序算法一定要手敲一遍(快排,堆排尤其重要)。了解一些新兴的技术。面试之后面试官都会问你有没有什么问题,千万不要没问题,也别傻乎乎的问一些敏感问题。了解你要面试的公司的产品及竞争产品。几个链接很多Java面试题更多Java面试题还是Java面试题总结无论是哪家公司,都很重视高并发高可用的技术,重视基础,重视JVM。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。如果这些文字能够帮到你,那就最好了,帮不到就当是我自己的一个记录。最后,希望大家都能找到适合自己的公司,开开心心的撸代码~我有一个微信公众号,经常会分享一些Java技术相关的干货;如果你喜欢我的分享,可以用微信搜索“Java团长”或者“javatuanzhang”关注。
天之道,损有余而补不足,是故虚胜实,不足胜有余。本文作者在一年之内参加过多场面试,应聘岗位均为 Java 开发方向。在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点。主要包括以下几个部分:Java 基础知识点Java 常见集合高并发编程(JUC 包)JVM 内存管理Java 8 知识点网络协议相关数据库相关MVC 框架相关大数据相关Linux 命令相关面试,是大家从学校走向社会的第一步。互联网公司的校园招聘,从形式上说,面试一般分为 2-3 轮技术面试 +1 轮 HR 面试。但是一些公司确实是没有 HR 面试的,直接就是三轮技术面。技术面试中,面试官一般会先就你所应聘的岗位进行相关知识的考察,也叫基础知识和业务逻辑面试。只要你回答的不是特别差,面试官通常会说:“咱们写个代码吧”,这个时候就开始了算法面试。也就是说,一轮技术面试 = 基础知识和业务逻辑面试 + 算法面试。在本篇文章中,我们主要从技术面试聊起。技术面试包括:业务逻辑和基础知识面试。首先是业务逻辑面试 ,也就是讲项目。面试官会对你简历上写的若干个项目其中之一拿出来和你聊聊。在期间,会针对你所做的东西进行深度挖掘。包括:为什么要这么做?优缺点分析,假如重新让你做一次,你打算怎么做? 等等。这个环节主要考察我们对自己做过的项目(实习项目或者校内项目)是否有一个清晰的认识。关于业务逻辑面试的准备,建议在平时多多思考总结,对项目的数据来源、整体运行框架都应该熟悉掌握。比如说你在某公司实习过程中,就可以进行总结,而不必等到快离职的时候慌慌张张的去总结该项目。接下来是基础知识面试。Java 开发属于后台开发方向,有人说后台开发很坑,因为需要学习的东西太多了。没错,这个岗位就是需要学习好多东西。包括:本语言(Java/C++/PHP)基础、数据库、网络协议、Linux 系统、计算机原理甚至前端相关知识都可以考察你,而且,并不超纲 。有时候,你报的是后台开发岗,并且熟悉的是 Java 语言,但是面试官却是 C++ 开发方向的,就是这么无奈~好了,闲话少说,让我们开始分类讲解常见面试知识点。(一) Java 基础知识点1)面向对象的特性有哪些?答:封装、继承和多态。2)Java 中覆盖和重载是什么意思?解析:覆盖和重载是比较重要的基础知识点,并且容易混淆,所以面试中常见。答:覆盖(Override)是指子类对父类方法的一种重写,只能比父类抛出更少的异常,访问权限不能比父类的小。被覆盖的方法不能是 private 的,否则只是在子类中重新定义了一个方法;重载(Overload)表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同。面试官: 那么构成重载的条件有哪些?答:参数类型不同、参数个数不同、参数顺序不同。面试官: 函数的返回值不同可以构成重载吗?为什么?答:不可以,因为 Java 中调用函数并不需要强制赋值。举例如下:如下两个方法:12void f(){}int f(){ return 1;}只要编译器可以根据语境明确判断出语义,比如在 int x = f();中,那么的确可以据此区分重载方法。不过, 有时你并不关心方法的返回值,你想要的是方法调用的其他效果 (这常被称为 “为了副作用而调用”),这时你可能会调用方法而忽略其返回值,所以如果像下面的调用:1fun();此时 Java 如何才能判断调用的是哪一个 f() 呢?别人如何理解这种代码呢?所以,根据方法返回值来区分重载方法是行不通的。3)抽象类和接口的区别有哪些?答:抽象类中可以没有抽象方法;接口中的方法必须是抽象方法;抽象类中可以有普通的成员变量;接口中的变量必须是 static final 类型的,必须被初始化 , 接口中只有常量,没有变量。抽象类只能单继承,接口可以继承多个父接口;Java8 中接口中会有 default 方法,即方法可以被实现。面试官:抽象类和接口如何选择?答:如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。如果知道某个类应该是基类,那么第一个选择的应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。4)Java 和 C++ 的区别:解析:虽然我们不太懂 C++,但是就是会这么问,尤其是三面(总监级别)面试中。答:都是面向对象的语言,都支持封装、继承和多态;指针:Java 不提供指针来直接访问内存,程序更加安全;继承: Java 的类是单继承的,C++ 支持多重继承; Java 通过一个类实现多个接口来实现 C++ 中的多重继承; Java 中类不可以多继承,但是!!!接口可以多继承;内存: Java 有自动内存管理机制,不需要程序员手动释放无用内存。5)Java 中的值传递和引用传递解析:这类题目,面试官会手写一个例子,让你说出函数执行结果,详细举例请查阅我的博客:Java 值传递和引用传递基础分析。答:值传递是指对象被值传递,意味着传递了对象的一个副本,即使副本被改变,也不会影响源对象。引用传递是指对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象的改变会反映到所有的对象上。6)JDK 中常用的包有哪些?答:java.lang、java.util、http://java.io、http://java.net、java.sql。7)JDK,JRE 和 JVM 的联系和区别:答:JDK 是 java 开发工具包,是 java 开发环境的核心组件,并提供编译、调试和运行一个 java 程序所需要的所有工具,可执行文件和二进制文件,是一个平台特定的软件。JRE 是 java 运行时环境,是 JVM 的实施实现,提供了运行 java 程序的平台。JRE 包含了 JVM,但是不包含 java 编译器 / 调试器之类的开发工具。JVM 是 java 虚拟机,当我们运行一个程序时,JVM 负责将字节码转换为特定机器代码,JVM 提供了内存管理 / 垃圾回收和安全机制等。这种独立于硬件和操作系统,正是 java 程序可以一次编写多处执行的原因。区别:JDK 用于开发,JRE 用于运行 java 程序;JDK 和 JRE 中都包含 JVM;JVM 是 java 编程语言的核心并且具有平台独立性。Others:限于篇幅,面试中 Java 基础知识点还有:反射、泛型、注解等。小结:本节主要阐述了 Java 基础知识点,这些问题主要是一面面试官在考察,难度不大,适当复习下,应该没什么问题。(二)Java 中常见集合集合这方面的考察相当多,这部分是面试中必考的知识点。1)说说常见的集合有哪些吧?答:Map 接口和 Collection 接口是所有集合框架的父接口:Collection 接口的子接口包括:Set 接口和 List 接口;Map 接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap 以及 Properties 等;Set 接口的实现类主要有:HashSet、TreeSet、LinkedHashSet 等;List 接口的实现类主要有:ArrayList、LinkedList、Stack 以及 Vector 等。(2)HashMap 和 Hashtable 的区别有哪些?(必问)答:HashMap 没有考虑同步,是线程不安全的;Hashtable 使用了 synchronized 关键字,是线程安全的;前者允许 null 作为 Key;后者不允许 null 作为 Key。3)HashMap 的底层实现你知道吗?答:在 Java8 之前,其底层实现是数组 + 链表实现,Java8 使用了数组 + 链表 + 红黑树实现。此时你可以简单的在纸上画图分析:4)ConcurrentHashMap 和 Hashtable 的区别? (必问)答:ConcurrentHashMap 结合了 HashMap 和 HashTable 二者的优势。HashMap 没有考虑同步,hashtable 考虑了同步的问题。但是 hashtable 在每次同步执行时都要锁住整个结构。 ConcurrentHashMap 锁的方式是稍微细粒度的。 ConcurrentHashMap 将 hash 表分为 16 个桶(默认值),诸如 get,put,remove 等常用操作只锁当前需要用到的桶。面试官:ConcurrentHashMap 的具体实现知道吗?答:该类包含两个静态内部类 HashEntry 和 Segment;前者用来封装映射表的键值对,后者用来充当锁的角色;Segment 是一种可重入的锁 ReentrantLock,每个 Segment 守护一个 HashEntry 数组里得元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment 锁。5)HashMap 的长度为什么是 2 的幂次方?答:通过将 Key 的 hash 值与 length-1 进行 & 运算,实现了当前 Key 的定位,2 的幂次方可以减少冲突(碰撞)的次数,提高 HashMap 查询效率;如果 length 为 2 的次幂 则 length-1 转化为二进制必定是 11111……的形式,在于 h 的二进制与操作效率会非常的快,而且空间不浪费;如果 length 不是 2 的次幂,比如 length 为 15,则 length-1 为 14,对应的二进制为 1110,在于 h 与操作,最后一位都为 0,而 0001,0011,0101,1001,1011,0111,1101 这几个位置永远都不能存放元素了,空间浪费相当大。更糟的是这种情况中,数组可以使用的位置比数组长度小了很多,这意味着进一步增加了碰撞的几率,减慢了查询的效率!这样就会造成空间的浪费。6)List 和 Set 的区别是啥?答:List 元素是有序的,可以重复;Set 元素是无序的,不可以重复。7)List、Set 和 Map 的初始容量和加载因子答:1. ListArrayList 的初始容量是 10;加载因子为 0.5; 扩容增量:原容量的 0.5 倍 +1;一次扩容后长度为 16。Vector 初始容量为 10,加载因子是 1。扩容增量:原容量的 1 倍,如 Vector 的容量为 10,一次扩容后是容量为 20。2. SetHashSet,初始容量为 16,加载因子为 0.75; 扩容增量:原容量的 1 倍; 如 HashSet 的容量为 16,一次扩容后容量为 323. MapHashMap,初始容量 16,加载因子为 0.75; 扩容增量:原容量的 1 倍; 如 HashMap 的容量为 16,一次扩容后容量为 328)Comparable 接口和 Comparator 接口有什么区别?答:前者简单,但是如果需要重新定义比较类型时,需要修改源代码。后者不需要修改源代码,自定义一个比较器,实现自定义的比较方法。具体解析参考我的博客:Java 集合框架—Set9)Java 集合的快速失败机制 “fail-fast”答:它是 java 集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作时,有可能会产生 fail-fast 机制。例如 :假设存在两个线程(线程 1、线程 2),线程 1 通过 Iterator 在遍历集合 A 中的元素,在某个时候线程 2 修改了集合 A 的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生 fail-fast 机制。原因: 迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变 modCount 的值。每当迭代器使用 hashNext()/next() 遍历下一个元素之前,都会检测 modCount 变量是否为 expectedmodCount 值,是的话就返回遍历;否则抛出异常,终止遍历。解决办法:在遍历过程中,所有涉及到改变 modCount 值得地方全部加上 synchronized;
 在Java相关的职位面试中,很多Java面试官都喜欢考察应聘者对Java并发的了解程度,以volatile关键字为切入点,往往会问到底,Java内存模型(JMM)和Java并发编程的一些特点都会被牵扯出来,再深入的话还会考察JVM底层实现以及操作系统的相关知识。接下来让我们在一个假想的面试过程中来学习一下volitile关键字吧。1. Java并发这块掌握的怎么样?来谈谈你对volatile关键字的理解吧。参考答案:我的理解是,被volatile修饰的共享变量,就会具有以下两个特性:保证了不同线程对该变量操作的内存可见性。禁止指令重排序。2. 那你可不可以详细的说一下究竟什么是内存可见性,什么又是重排序?参考答案:这个要是说起来可就多了,我就从Java内存模型开始说起吧。Java虚拟机规范试图定义一个Java内存模型(JMM),以屏蔽所有类型的硬件和操作系统内存访问差异,让Java程序在不同的平台上能够达到一致的内存访问效果。简单地说,由于CPU执行指令的速度很快,但是内存访问速度很慢,差异不是一个量级,所以搞处理器的那群大佬们又在CPU里加了好几层高速缓存。在Java内存模型中,对上述优化进行了一波抽象。JMM规定所有的变量都在主内存中,类似于上面提到的普通内存,每个线程又包含自己的工作内存,为了便于理解可以看成CPU上的寄存器或者高速缓存。因此,线程的操作都是以工作内存为主,它们只能访问自己的工作内存,并且在工作之前和之后,该值被同步回主内存。说的我自己都有点晕了,用一张图来帮助我们理解吧:线程执行的时候,将首先从主内存读值,再load到工作内存中的副本中,然后传给处理器执行,执行完毕后再给工作内存中的副本赋值,随后工作内存再把值传回给主存,主存中的值才更新。使用工作内存和主存,虽然加快了速度,但也带来了一些问题。例如:i = i + 1;假设 i 的初始值为 0 ,当只有一个线程执行它的时候,结果肯定是 1 ,那么当两个线程执行时,得到的结果会是 2 吗?不一定。可能会存在这种情况:线程1: load i from 主存 // i = 0i + 1 // i = 1线程2: load i from主存 // 因为线程1还没将i的值写回主存,所以i还是0i + 1 //i = 1线程1: save i to 主存线程2: save i to 主存如果两个线程遵循上面的执行过程,那么 i 的最终值竟然是 1 。如果最后的写回生效的慢,你再读取 i 的值,都可能会是 0 ,这就是缓存不一致的问题。接下来就要提到您刚才所问的问题了,JMM主要围绕在并发过程中如何处理并发原子性、可见性和有序性这三个特征来建立的,通过解决这三个问题,就可以解决缓存不一致的问题。而volatile跟可见性和有序性都有关。3. 那你具体说说这三个特性呢?1 . 原子性(Atomicity):在Java中,对基本数据类型的读取和赋值操作是原子性操作,所谓原子性操作就是指这些操作是不可中断的,要做一定做完,要么就没有执行。 例如:i = 2;j = i;i++;i = i + 1;以上四个操作, i = 2 是一个读取操作,肯定是原子性操作, j = i 你觉得是原子性操作,但事实上,可以分为两个步骤,一个是读取 i 的值,然后再把值赋给 j ,这已经是两步操作了,不能称为原子操作,i++ 和 i = i + 1 是等效的,读的值,+ 1,然后写回主存,这是三个步骤的操作了。在上面的例子中,最后一个值可能在各种情况下,因为它不会满足原子性。在本例中,只有一个简单的读取,赋值是一个原子操作,并且只能被分配给一个数字,使用变量来读取变量的值的操作。一个例外是,在虚拟机规范中允许64位数据类型(long和double),它被划分为两个32位操作,但是JDK的最新实现实现了原子操作。JMM只实现基本的原子性,比如上面的i++操作,它必须依赖于同步和锁定,以确保整个代码块的原子性。在释放锁之前,线程必须将I的值返回到主内存。2 . 可见性(Visibility):说到可见性,Java使用volatile来提供可见性。当一个变量被volatile修改时,它的变化会立即被刷新到主存,当其他线程需要读取变量时,它会读取内存中的新值。普通变量不能保证。事实上,同步和锁定也可以保证可见性。在释放锁之前,线程将把共享变量值刷回主内存,但是同步和锁更昂贵。3 . 有序性(Ordering)JMM允许编译器和处理器重新排序指令,但是指定了as-if-串行语义,也就是说,无论重新排序,程序的执行结果都不能更改。例如:double pi = 3.14; //Adouble r = 1; //Bdouble s= pi * r * r;//C上面的语句中,可以按照C - > B - >,结果是3.14,但它也可以按照的顺序B - > - > C,因为A和B是两个单独的语句,并依赖,B,C和A和B可以重新排序,但C不能行前面的A和B。JMM确保重新排序不会影响单线程的执行,但容易出现多线程问题。例如,这样的代码:int a = 0;bool flag = false;public void write() {a = 2; //1flag = true; //2}public void multiply() {if (flag) { //3int ret = a * a;//4}}如果有两个线程执行上面的代码段,线程1首先执行写,然后再乘以线程2。最后,ret的值必须是4?不一定:如图1和2所示,在写方法中进行重新排序,线程1对第一个赋值为true,然后执行到线程2,ret直接计算结果,然后再执行线程1,这一次的CaiFu值为2,显然是较晚的步骤。此时要标记加上volatile关键字,重新排序,可以确保程序的“顺序”,也可以基于重量级的同步和锁定来确保,他们可以确保在代码执行的区域内一次性完成。此外,JMM有一些内在的规律性,也就是说,没有任何方法可以保证有序,这通常称为发生在原则之前。<< jsr-133: Java内存模型和线程规范>>定义了以下事件:程序顺序规则: 一个线程中的每个操作,happens-before于该线程中的任意后续操作监视器锁规则:对一个线程的解锁,happens-before于随后对这个线程的加锁volatile变量规则: 对一个volatile域的写,happens-before于后续对这个volatile域的读传递性:如果A happens-before B ,且 B happens-before C, 那么 A happens-before Cstart()规则: 如果线程A执行操作ThreadB_start()(启动线程B) , 那么A线程的ThreadB_start()happens-before 于B中的任意操作join()原则: 如果A执行ThreadB.join()并且成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。interrupt()原则: 对线程interrupt()方法的调用先行发生于被中断线程代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测是否有中断发生finalize()原则:一个对象的初始化完成先行发生于它的finalize()方法的开始第1条程序顺序规则在一个线程中,所有的操作都是有序的,但实际上只要JMM的执行结果允许重新排序,这也是发生的重点——单线程执行结果是正确的,但是也不能保证多线程。规则2,规则监视器的规则,非常好理解。在锁被添加之前,锁已经被释放,然后它才能继续被锁定。第三条规则适用于讨论的不稳定性。如果一个行程序编写一个变量,另一个线程读取它,那么在操作之前必须读取写入操作。第四个规则正在发生。接下来的几行不会重复。4. volatile关键字如何满足并发编程的三大特性的?重新引入volatile变量规则是很重要的:对于一个不稳定域的写,出现之前,然后是对这个volatile字段的读取。本文进行再次说,如果一个变量声明事实上是不稳定,所以当我读了变量,最新的价值总是可以阅读它,这个最新的值意味着无论什么其他线程写操作,该变量将立即更新到主内存,我也可以从主内存读取只写值。也就是说,volatile关键字保证了可视性和有序度。继续上面的代码示例:int a = 0;bool flag = false;public void write() {a = 2; //1flag = true; //2}public void multiply() {if (flag) { //3int ret = a * a;//4}}当编写一个volatile变量时,JMM在本地内存中刷新与主内存对应的本地内存中的共享变量。当您读取一个volatile变量时,JMM将使线程对应的本地内存失效,然后线程将从主内存读取共享变量。