SpringMvc面试题 https://juejin.im/post/5cc2de6f5188252d9109875d

面试中必问的JVM应该怎么学 https://juejin.im/post/5cc3b95051882525082e1c99

面试官:你用过哪些JDK自带的命令行工具 https://juejin.im/post/5ccbd09af265da037129ada0

 

 

 

碰到问题:
1. js如何创建对象: https://www.jianshu.com/p/57425495d6ac 一、构造函数法,成员和方法可以使用this或者prototype,二、Object.create() 方法;
2. sql优化 这大概是最全的sql优化方案了:https://zhuanlan.zhihu.com/p/48385127 58到家数据库30条军规解读:https://www.mekau.com/4917.html
1. 避开查询的模糊匹配,业务细化或者临时表解决,除非必要,否则不要在关键词前加%。
2. 增加索引,尽量在条件使用索引
3. 不要把SQL语句写得太复杂
4. 条件的顺序: 先过滤大表,再过滤小表,过滤大表放右边
ORACLE 采用自下而上从右到左的顺序解析Where 子句,根据这个原理,
A:表之间的连接必须写在其他Where 条件之前,
B:可以过滤掉最大数量记录的条件必须写在Where 子句的末尾
C:对一个条件来说,驱动表条件放等号左边
5. 表的顺序: 表名(最后面的那个表名为驱动表,执行顺序为从后往前, 所以数据量较少的表尽量放后),
oracle 的解析器按照从右到左的顺序处理,FROM 子句中的表名,FROM 子句中写在最后的表(基础表 driving table)将被最先处理,即最后的表为驱动表,在FROM 子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3 个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指被其他表所引用的表

表应按结果记录数从大到小的顺序从左到右来排列,因为表间连接时,最右边的表会被放到嵌套循环的最外层。最外层的循环次数越少,效率越高。
一句话,数据量少或者交叉表放右边做驱动表(基础表)

3. set和list,map的区别,Hash比较快
list:注重独顺序。ArrayList,LinkArray
Set:注重值的独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素。HashSet,TreeSet
map:注重映射,Key的独一无二的性质。hashMap,TreeMap,Hashtable(线程安全),ConcurrentHashMap(线程安全)
4. 内存分析
5. js慢的原因,优化: https://segmentfault.com/a/1190000008273435
JavaScript加载和执行
1.阻塞式脚本:合并文件(减少http请求),将script标签放在body尾部(减少页面css,html的下载阻塞,减少界面的空白时间(浏览器在解析到script标签之前,不会渲染页面的任何部分))
2.无阻塞式脚本:延迟脚本和动态脚本均不阻塞,即下载过程不阻塞其他进程
延迟脚本: defer和async属性:都是并行下载,下载过程不阻塞,区别在于执行时机,async是下载完成后立即执行;defer是等页面加载完成后再执行。defer仅当src属性声明时才生效(HTML5的规范)
动态脚本: 动态添加script标签,返回的代码通常会立刻执行,所以,为了确保脚本下载完成且准备就绪后才执行,须侦听load事件。将script添加到head中比添加到body中更保险。
数据存取
将全局变量存储到局部变量中:因为全局变量总是存在于执行环境作用域链的最末端,所以,访问全局变量是最慢的,访问局部变量是最快的。尤其是对于未优化过的JavaScript引擎。
尽量避免使用with,try-catch,eval等动态作用域语句,因为JavaScript引擎无法通过静态分析的方法进行优化。
闭包会影响性能(作用域链加深)和可能导致内存泄漏(IE中)
总结:
使用对象字面量代替对象
使用局部变量存储全局变量和对象成员
尽量不用with,eval语句,try-catch的catch子句要谨慎使用
嵌套越深,性能越差,尽量少用。
字符串拼接推荐用+ +=,推荐写法:str=str+’one’+”two”;(将str写在左侧)
算法和流程控制
for…in的循环性能最差(因为它需要搜索实例和原型上的所有属性),除非,你需要遍历一个属性数量未知的对象,否则不要使用它。
更不要用它遍历数组成员。其余的循环性能都差不多。
倒序循环,把减法操作放到控制条件中,例如:k–,这样只是比较“它是true吗?”速度更快。
forEach()比数组循环慢,如果对性能有极致要求,还是用数组循环好。
当判断值多于2个时,使用switch,否则用if-else (数量少时,性能差别不大,可根据个人喜好使用)。若判断值很多,且没有什么复杂的操作,可以用数组代替switch。
在JavaScript中,switch使用全等操作符,不会发生类型转换的损耗。
把最可能出现的条件放在首位。
调用栈溢出错误基本都是由递归导致的:不正确的终止条件;包含了太多递归,超过了浏览器的调用栈限制。把递归算法改用迭代算法实现是避免调用栈溢出错误的解决方法之一。
缓存:避免重复性工作,手动实现缓存(Vue源码中就有很多缓存)

6. java慢的原因
7. js对象创建依赖怎么解决, spring里面的java相互依赖注入怎么解决
java:
Spring-bean的循环依赖以及解决方式: https://blog.csdn.net/u010853261/article/details/77940767
spring是如何解决对象相互依赖的: https://blog.csdn.net/shenjianzhuang/article/details/79032469
第一种,解决setter对象的依赖,就是说在A类需要设置B类,B类需要设置C类,C类需要设置A类,这时就出现一个死循环,
spring的解决方案是,初始化A类时把A类的初始化Bean放到缓存中,然后set B类,再把B类的初始化Bean放到缓存中,
然后set  C类,初始化C类需要A类和B类的Bean,这时不需要初始化,只需要从缓存中取出即可.
该种仅对single作用的Bean起作用,因为prototype作用的Bean,Spring不对其做缓存
第二种,解决构造器中对其它类的依赖,创建A类需要构造器中初始化B类,创建B类需要构造器中初始化C类,创建C类需要构造器中又要初始化A类,因而形成一个死循环,Spring的解决方案是,把创建中的Bean放入到一个“当前创建Bean池”中,在初始化类的过程中,如果发现Bean类已存在,就抛出一个“BeanCurrentInCreationException”的异常

8. jvm知识
9. vue学习

 

 

 

 

 

一、Java 基础
=============================================================================
1.JDK 和 JRE 有什么区别?
JDK就是Java Development Kit.简单的说JDK是面向开发人员使用的SDK,它提供了Java的开发环境和运行环境。SDK是Software Development Kit 一般指软件开发包,可以包括函数库、编译程序等。
JRE是Java Runtime Enviroment是指Java的运行环境,是面向Java程序的使用者,而不是开发者。
如果安装了JDK,会发同你的电脑有两套JRE,一套位于 \jre 另外一套位于 C:\Program Files\Java\jre1.5.0_15 目录下,后面这套比前面那套少了Server端的Java虚拟机,不过直接将前面那套的Server端Java虚拟机复制过来就行了。而且在安装JDK可以选择是否安装这个位于 C:\Program Files\Java 目录下的JRE。如果你只安装JRE,而不是JDK,那么只会在 C:\Program Files\Java 目录下安装唯一的一套JRE。

2.== 和 equals 的区别是什么?
==是比较内存位置, equals先比较内存位置,后比较内容(string为例)

3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
两个对象不相同,hashcode可能相同
equals(Object obj)方法用来判断两个对象是否“相同”,如果“相同”则返回true,否则返回false。
hashcode()方法返回一个int数,在Object类中的默认实现是“将该对象的内部地址转换成一个整数返回”。
接下来有两个个关于这两个方法的重要规范(我只是抽取了最重要的两个,其实不止两个):
规范1:若重写equals(Object obj)方法,有必要重写hashcode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashcode()返回值。说得简单点就是:“如果两个对象相同,那么他们的hashcode应该 相等”。不过请注意:这个只是规范,如果你非要写一个类让equals(Object obj)返回true而hashcode()返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了Java规范,程序也就埋下了BUG。
规范2:如果equals(Object obj)返回false,即两个对象“不相同”,并不要求对这两个对象调用hashcode()方法得到两个不相同的数。说的简单点就是:“如果两个对象不相同,他们的hashcode可能相同”。
根据这两个规范,可以得到如下推论:
1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。
2、如果两个对象不equals,他们的hashcode有可能相等。
3、如果两个对象hashcode相等,他们不一定equals。
4、如果两个对象hashcode不相等,他们一定不equals。

4.final 在 java 中有什么作用?
1.修饰类   当用final修饰一个类时,表明这个类不能被继承。
2.修饰方法 使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。
3.修饰变量 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

5.java 中的 Math.round(-1.5) 等于多少?
等于 -1 , 四舍五入的原理是在参数上加0.5然后进行下取整

6.String 属于基础的数据类型吗?
String不是基本数据类型,而是一个类(class),是Java编程语言中的字符串。

7.java 中操作字符串都有哪些类?它们之间有什么区别?
String:提供了String 类来创建和操作字符串
StringBuffer:线程同步
StringBuilder:线程不同步,单线程时建议使用

8.String str=”i”与 String str=new String(“i”)一样吗?
前者常量区创建,后者在堆区创建 https://blog.csdn.net/K_122/article/details/76170426
String str1=”java”;//指向字符串池
String str2=”blog”;//指向字符串池
String s = str1+str2;
+运算符会在堆中建立起两个String对象,这两个对象的值分别是“java”,”blog”,也就是说从字符串常量池中复制这两个值,然后再堆中创建两个对象。然后再建立对象s,然后将“javablog”的堆地址赋给s. 这句话共创建了3个String对象。

9.如何将字符串反转? https://josh-persistence.iteye.com/blog/2205772
二分递归地将后面的字符和前面的字符连接起来。
取得当前字符并和之前的字符append起来
将字符从后往前的append起来
和StringBuffer()一样,都用了Java自实现的方法,使用位移来实现
和StringBuilder()一样,都用了Java自实现的方法,使用位移来实现
二分交换,将后面的字符和前面对应的那个字符交换
基于栈先进后出的原理
例子:
String string=”runoob”;
String reverse = new StringBuffer(string).reverse().toString();
String reverse = new StringBuilder(string).reverse().toString();

10.String 类的常用方法都有那些?
length()//返回该字符串的长度
charAt(int index)//返回字符串中指定位置的字符
substring(int beginIndex)//该方法从beginIndex位置起,从当前字符串中取出剩余的字符作为一个新的字符串返回。
substring(int beginIndex, int endIndex)//该方法从beginIndex位置起,从当前字符串中取出到endIndex-1位置的字符作为一个新的字符串返回。
compareTo(String anotherString)//该方法是对字符串内容按字典顺序进行大小比较

11.抽象类必须要有抽象方法吗?
抽象类中可以没有抽象方法,但有抽象方法的一定是抽象类

12.普通类和抽象类有哪些区别?
1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
2)抽象类不能用来创建对象;
3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。

13.抽象类能使用 final 修饰吗?
能,这种类不能被继承。

14.接口和抽象类有什么区别?
抽象类可以有默认的方法实现完全是抽象的。接口根本不存在方法的实现。
抽象类可以有构造器,而接口不能有构造器
抽象方法可以有public、protected和default这些修饰符, 接口方法默认修饰符是public。你不可以使用其它修饰符。
抽象类在java语言中所表示的是一种继承关系,一个子类只能存在一个父类,但是可以存在多个接口。
抽象方法比接口速度要快,接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。

15.java 中 IO 流分为几种?
根据处理数据的数据类型的不同可以分为:字节流(抽象基类为InPutStream和OutPutStream)和字符流(抽象基类为Reader和Writer)。
1.字节流读取的时候,读到一个字节就返回一个字节; 字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在UTF-8码表中是3个字节)时。先去查指定的编码表,将查到的字符返回。
2.字节流可以处理所有类型数据,如:图片,MP3,AVI视频文件,而字符流只能处理字符数据。只要是处理纯文本数据,就要优先考虑使用字符流,除此之外都用字节流。

根据流向不同,可以分为:输入流和输出流。Java中IO流分成两大类,一种是输入流,所有的输入流都直接或间接继承自InputStream抽象类,输入流作为数据的来源,我们可以通过输入流的read方法读取字节数据;另一种是输出流,所有的输出流都直接或间接继承自OutputStream抽象类,输出流接收数据,可以通过write方法写入字节数据。

16.BIO、NIO、AIO 有什么区别https://blog.csdn.net/skiof007/article/details/52873421
IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。
BIO模式,需要先在服务端启动一个ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,如果有的话,客户端会线程会等待请求结束后才继续执行。

NIO本身是基于事件驱动思想来完成的,其主要想解决的是BIO的大并发问题: 在使用同步I/O的网络应用中,如果要同时处理多个客户端请求,或是在客户端要同时和多个服务器进行通讯,就必须使用多线程来处理。也就是说,将每一个客户端请求分配给一个线程来单独处理。这样做虽然可以达到我们的要求,但同时又会带来另外一个问题。由于每创建一个线程,就要为这个线程分配一定的内存空间(也叫工作存储器),而且操作系统本身也对线程的总数有一定的限制。如果客户端的请求过多,服务端程序可能会因为不堪重负而拒绝客户端的请求,甚至服务器可能会因此而瘫痪。

AIO与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作系统主动通知应用程序。 即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。

17.File的常用方法都有哪些
String getName():返回此File对象所表示的文件名或路径名(如果是路径,则返回最后一级子路径名)。
String getPath():返回此File对象所对应的路径名。
File getAbsoluteFile():返回此File对象的绝对路径。
String getAbsolutePath():返回此File对象所对应的绝对路径名。
String getParent():返回此File对象所对应目录(最后一级子目录)的父目录名。
boolean renameTo(File newName):重命名此File对象所对应的文件或目录,如果重命名成功,则返回true;否则返回false

二、容器
=============================================================================
18.java 容器都有哪些
Java容器类类库的用途是“持有对象”,并将其划分为两个不同的概念:
1)Collection:一个独立元素的序列,这些元素都服从一条或者多条规则。 List必须按照插入的顺序保存元素,而set不能有重复的元素。Queue按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)。 LinkedList,ArrayList,Vector等。
2)Map:一组成对的“键值对”对象,允许你使用键来查找值。 Hashtable,HashMap

19.Collection 和 Collections 有什么区别
Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。
Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

20.List、Set、Map 之间的区别是什么https://blog.csdn.net/SpeedMe/article/details/22398395
List的特征是其元素以线性方式存储,集合中可以存放重复对象。
Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。
Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。 Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。

21.HashMap 和 Hashtable 有什么区别https://blog.csdn.net/bruce_suxin/article/details/78787875
主要的区别有:线程安全性,同步(synchronization),以及速度。
第一、继承不同。
public class Hashtable extends Dictionary implements Map
public class HashMap extends AbstractMap implements Map
第二、Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。
第三、Hashtable中,key和value都不允许出现null值。在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键, 也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
第四、两个遍历方式的内部实现上不同。Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。
第五、哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。
第六、Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

22.如何决定使用 HashMap 还是 TreeMap
HashMap 非线程安全 TreeMap 非线程安全
HashMap:适用于在Map中插入、删除和定位元素。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),建议多使用HashMap,在需要排序的Map时候才用TreeMap。

23.说一下 HashMap 的实现原理
通过hash的方法,通过put和get存储和获取对象。存储对象时,我们将K/V传给put方法时,它调用hashCode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前bucket的占用情况自动调整容量(超过Load Facotr则resize为原来的2倍)。获取对象时,我们将K传给get,它调用hashCode计算hash从而得到bucket位置,并进一步调用equals()方法确定键值对。如果发生碰撞的时候,Hashmap通过链表将产生碰撞冲突的元素组织起来,在Java 8中,如果一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提高速度。

24.说一下 HashSet 的实现原理
对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,我们应该为保存到 HashSet 中的对象覆盖 hashCode() 和 equals()
HashSet中不允许有重复元素,这是因为HashSet是基于HashMap实现的,HashSet中的元素都存放在HashMap的key上面,而value中的值都是统一的一个private static final Object PRESENT = new Object();。HashSet跟HashMap一样,都是一个存放链表的数组。

25.ArrayList 和 LinkedList 的区别是什么
ArrayList是实现了基于动态数组的结构,而LinkedList则是基于实现链表的数据结构。而两种数据结构在程序上体现出来的优缺点在于增删和改查的速率。
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据

26.如何实现数组和 List 之间的转换
1. List转换成为数组。(这里的List的实体是ArrayList),调用ArrayList的toArray方法。
2. 数组转换成为List。调用Arrays的asList方法。

27.ArrayList 和 Vector 的区别是什么
1. ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
2. Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
3. LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。

28.Array 和 ArrayList 有何区别
Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。
Array大小是固定的,ArrayList的大小是动态变化的。 ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。

29.在 Queue 中 poll()和 remove()有什么区别
1、add()和offer()区别:add()和offer()都是向队列中添加一个元素。一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,调用 add() 方法就会抛出一个 unchecked 异常,而调用 offer() 方法会返回 false。因此就可以在程序中进行有效的判断!
2、poll()和remove()区别:remove() 和 poll() 方法都是从队列中删除第一个元素。如果队列元素为空,调用remove() 的行为与 Collection 接口的版本相似会抛出异常,但是新的 poll() 方法在用空集合调用时只是返回 null。因此新的方法更适合容易出现异常条件的情况。
3、element() 和 peek() 区别:element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null。

30.哪些集合类是线程安全的
Vector:就比Arraylist多了个同步化机制(线程安全)。
Hashtable:就比Hashmap多了个线程安全。
ConcurrentHashMap:是一种高效但是线程安全的集合。
Stack:栈,也是线程安全的,继承于Vector。

31.迭代器 Iterator 是什么
关于Iterator的简单的解释Iterator提供了同意遍历操作集合元素的统一接口,Collection接口实现了Iterable接口,每个集合都通过实现Iterable接口中的iterator()方法返回Iterator接口的实例,然后对集合的元素进行迭代操作
Iterator接口提供了很多对集合元素进行迭代的方法。每一个集合类都包括了可以返回迭代器实例的迭代方法。迭代器可以在迭代过程中删除底层集合的元素,但是不可以直接调用集合的remove(Object obj)删除,可以通过迭代器的remove()方法删除

32.Iterator 怎么使用?有什么特点
Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。

33.Iterator 和 ListIterator 有什么区别
一、ListIterator有add()方法,可以向List中添加对象,而Iterator不能。
二、ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历。但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。也就是说Iterator是单向的,而ListIterator是双向的。IListIterator继承自Iterator。
三、ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator 没有此功能。
四、都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。因为ListIterator的这些功能,可以实现对LinkedList等List数据结构的操作。

34.怎么确保一个集合不能被修改
java中不可变ArrayList
使用JDK,首先,jdk提供了漂亮的方式从已经存在的集合中获得不可修改的集合:Collections.unmodifiableList(list);
使用Guava,Guava提供类似功能,创建了ImmutableList来实现

集合不能被修改
使用Collections.unmodifiableCollection(Collection c)方法创建一个只读集合,这将确保改变集合的任何操作都会抛出UnsupportedOperationException。

三、多线程
=============================================================================
35.并行和并发有什么区别
并发:一个处理器同时处理多个任务。
并行:多个处理器或者是多核的处理器同时处理多个不同的任务.
前者是逻辑上的同时发生(simultaneous),而后者是物理上的同时发生.
并发性(concurrency),又称共行性,是指能处理多个同时性活动的能力,并发事件之间不一定要同一时刻发生。
并行(parallelism)是指同时发生的两个并发事件,具有并发的含义,而并发则不一定并行。
来个比喻:并发和并行的区别就是一个人同时吃三个馒头和三个人同时吃三个馒头。

36.线程和进程的区别
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
2) 线程的划分尺度小于进程,使得多线程程序的并发性高。
3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
4) 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

37.守护线程是什么
在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程) 。Daemon的作用是为其他线程的运行提供服务,比如说GC线程。其实User Thread线程和Daemon Thread守护线程本质上来说去没啥区别的,唯一的区别之处就在虚拟机的离开:如果User Thread全部撤离,那么Daemon Thread也就没啥线程好服务的了,所以虚拟机也就退出了。

38.创建线程有哪几种方式
1. 继承Thread类创建线程类
2. 通过Runable接口创建线程类
3. 通过Callable和FutureTask创建线程
4. 通过线程池创建线程

39.说一下 runnable 和 callable 有什么区别
(1)Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的
(2)Callable规定的方法是call(),Runnable规定的方法是run()
(3)Callable的任务执行后可返回值,而Runnable的任务是不能返回值(是void)
(4)call方法可以抛出异常,run方法不可以
(5)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。
(6)加入线程池运行,Runnable使用ExecutorService的execute方法,Callable使用submit方法。

40.线程有哪些状态
线程状态总的可分为五大状态:分别是生、死、可运行、运行、等待/阻塞/睡眠。

41.sleep() 和 wait() 有什么区别
sleep()是线程线程类(Thread)的方法,调用会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,调用会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才会进入锁池,不再次获得对象锁才会进入运行状态;

42.notify()和 notifyAll()有什么区别
调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争。

43.线程的 run()和 start()有什么区别
总结一下:
start() 可以启动一个新线程,run()不能
start()不能被重复调用,run()可以
start()中的run代码可以不执行完就继续执行下面的代码,即进行了线程切换。直接调用run方法必须等待其代码全部执行完才能继续执行下面的代码。
start() 实现了多线程,run()没有实现多线程。

44.创建线程池有哪几种方式
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

45.线程池都有哪些状态
线程池的5种状态:Running、ShutDown、Stop、Tidying、Terminated。
RUNNING
(1) 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。
(02) 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0!
SHUTDOWN
(1) 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。
(2) 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。
STOP
(1) 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。
(2) 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。
TIDYING
(1) 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。
(2) 状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。
当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。

TERMINATED
(1) 状态说明:线程池彻底终止,就变成TERMINATED状态。
(2) 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。

46.线程池中 submit()和 execute()方法有什么区别
1、接收的参数不一样
2、submit有返回值,而execute没有

47.在 java 程序中怎么保证多线程的运行安全
当多个线程要共享一个实例对象的值得时候,那么在考虑安全的多线程并发编程时就要保证下面3个要素:
原子性(Synchronized, Lock)
有序性(Volatile,Synchronized, Lock)
可见性(Volatile,Synchronized,Lock)
当然由于synchronized和Lock保证每个时刻只有一个线程执行同步代码,所以是线程安全的,也可以实现这一功能,但是由于线程是同步执行的,所以会影响效率。

48.多线程锁的升级原理是什么

49.什么是死锁
所谓死锁,是指多个进程循环等待它方占有的资源而无限期地僵持下去的局面

50.怎么防止死锁
避免死锁的几种方式:置加锁顺序, 设置加锁时限, 死锁检测

51.ThreadLocal 是什么?有哪些使用场景
ThreadLocal提供了线程的局部变量,每个线程都可以通过set()和get()来对这个局部变量进行操作,但不会和其他线程的局部变量进行冲突,实现了线程的数据隔离~。
简要言之:往ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。

52.说一下 synchronized 底层实现原理

53.synchronized 和 volatile 的区别是什么

54.synchronized 和 Lock 有什么区别

55.synchronized 和 ReentrantLock 区别是什么

56.说一下 atomic 的原理

四、反射
=============================================================================
57.什么是反射
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

58.什么是 java 序列化?什么情况下需要序列化
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化,将数据分解成字节流,以便存储在文件中或在网络上传输。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。 序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流;
序列化分为两大部分:序列化和反序列化。序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。恢复数据要求有恢复数据的对象实例

序列化是用来通信的,服务端把数据序列化,发送到客户端,客户端把接收到的数据反序列化后对数据进行操作,完成后再序列化发送到服务端,服务端再反序列化数据后对数据进行操作。说白了,数据需要序列化以后才能在服务端和客户端之间传输。这个服务端和客户端的概念是广义的,可以在网络上,也可以在同一台机器的不同进程中,甚至在同一个进程中进行通信。在传统编程中,对象是通过调用栈间接的与客户端交互,但在面向服务的编程中,客户端永远都不会直接调用实例。不序列化也可以传输,但是无法跨平台,安全性也无法保障。

59.动态代理是什么?有哪些应用
动态代理是一种在运行时动态地创建代理对象,动态地处理代理方法调用的机制。
动态代理实际上有很多应用,比如spring aop的实现,rpc框架的实现

60.怎么实现动态代理
动态代理主要有两种实现方式,一种是JDK动态代理,一种是CGLIB字节码机制,当然还有Javassist或ASM库.
JDK动态代理就是通过反射机制实现的。
利用CGLIB实现动态代理, cglib是一种基于ASM的字节码生成库,用于生成和转换Java字节码.
ASM是一个轻量但高性能的字节码操作框架。cglib是基于ASM的上层应用,对于代理没有实现接口的类,cglib非常实用。

五、对象拷贝
=============================================================================
61.为什么要使用克隆
a. 获得一个对象的拷贝(此处指深层拷贝)使用赋值操作符“=”是不能完成的;
b. 无需调用构造函数即可获得对象的拷贝(当然,拷贝对象和被克隆对象之间是否影响取决于深克隆还是浅克隆),一定程度上可以提高执行效率。
Java Object类提供了一个protected修饰的clone()方法,该方法用于帮助其他对象来实现“自我克隆”,所谓“自我克隆”就是得到一个当前对象的副本,而且两者之间完全隔离,该方法只能被子类重写或调用。

62.如何实现对象克隆
利用Object类的clone()方法。必须要遵循下面三点:
1.在派生类中覆盖基类的clone()方法,并声明为public【Object类中的clone()方法为protected的】。
2.在派生类的clone()方法中,调用super.clone()。
3.在派生类中实现Cloneable接口。 Object类里的clone方法是浅复制(浅克隆)

63.深拷贝和浅拷贝区别是什么
Java里的clone分为:
A:浅复制(浅克隆): **浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
B:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍。

 

 

六、Java Web
=============================================================================
64.jsp 和 servlet 有什么区别

65.jsp 有哪些内置对象?作用分别是什么

66.说一下 jsp 的 4 种作用域

67.session 和 cookie 有什么区别

68.说一下 session 的工作原理

69.如果客户端禁止 cookie 能实现 session 还能用吗
可以。可以在url中传递sessionID

70.spring mvc 和 struts 的区别是什么
Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文
Struts2需要针对每个request进行封装,把request,session等servlet生命周期的变量封装成一个一个Map
SpringMVC的方法之间基本上独立的,独享request response数据
SpringMVC的入口是servlet,而Struts2是filter
拦截器实现机制上,Struts2有以自己的interceptor机制,SpringMVC用的是独立的AOP方式,这样导致Struts2的配置文件量还是比SpringMVC大。
SpringMVC开发效率和性能高于Struts2
Struts2更加符合OOP的编程思想, SpringMVC就比较谨慎,在servlet上扩展

71.如何避免 sql 注入

72.什么是 XSS 攻击,如何避免 https://blog.csdn.net/lamp_yang_3533/article/details/52431059
XSS是跨站脚本攻击的缩写,是一种网站应用程序的安全漏洞攻击,是代码注入的一种。 通常是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。
两种方式来预防 XSS 攻击。
对用户输入的数据进行过滤。
对视图模板中输出的数据进行过滤。

73.什么是 CSRF 攻击,如何避免https://blog.csdn.net/lamp_yang_3533/article/details/79959071
CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,是一种对网站的恶意攻击。 … XSS 利用的是站点内的信任用户,而CSRF 则通过伪装成(假冒)站点内的信用用户,执行该用户不知情的操作。
防御 CSRF 的几种策略
目前防御 CSRF 攻击主要有三种策略:
验证 HTTP Referer 字段
在请求地址中添加 token 并验证
在 HTTP 头中自定义属性并验证

补充:
Http的原理
Https的原理

 

 

七、异常
=============================================================================
74.throw 和 throws 的区别
throw是语句抛出一个异常。
throws是方法可能抛出异常的声明

75.final、finally、finalize 有什么区别
final 用于申明属性,方法和类,表示属性不可变,方法不可以被覆盖,类不可以被继承。
finally 是异常处理语句结构中,表示总是执行的部分。
finallize 表示是object类一个方法,在垃圾回收机制中执行的时候会被调用被回收对象的方法。允许回收此前未回收的内存垃圾。所有object都继承了 finalize()方法

76.try-catch-finally 中哪个部分可以省略

77.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗
finally块中的内容会先于try中的return语句执行,如果finall语句块中也有return语句的话,那么直接从finally中返回了,这也是不建议在finally中return的原因。
1、不管有没有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算之后执行的;

78.常见的异常类有哪些

八、网络
=============================================================================
79.http 响应码 301 和 302 代表的是什么?有什么区别https://www.jianshu.com/p/995a3000f7d6
301 redirect: 301 代表永久性转移(Permanently Moved)
302 redirect: 302 代表暂时性转移(Temporarily Moved )

80.forward 和 redirect 的区别

81.简述 tcp 和 udp的区别
1。TCP是基于连接的,UDP是基于无连接
2。对系统资源的要求(TCP较多,UDP少)
3。UDP程序结构较简单
4。流模式与数据报模式
5。TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,速度慢;UDP不保证,速度快。

82.tcp 为什么要三次握手,两次不行吗?为什么

83.说一下 tcp 粘包是怎么产生的

84.OSI 的七层模型都有哪些

85.get 和 post 请求有哪些区别

86.如何实现跨域
1、jsonp, 最常见的一种跨域方式,其背后原理就是利用了script标签不受同源策略的限制,在页面中动态插入了script,script标签的src属性就是后端api接口的地址,并且以get的方式将前端回调处理函数名称告诉后端,后端在响应请求时会将回调返还,并且将数据以参数的形式传递回去。
2. CORS, Cross-Origin Resource Sharing(跨域资源共享)是一种允许当前域(origin)的资源(比如html/js/web service)被其他域(origin)的脚本请求访问的机制。当使用XMLHttpRequest发送请求时,浏览器如果发现违反了同源策略就会自动加上一个请求头:origin,后端在接受到请求后确定响应后会在Response Headers中加入一个属性:Access-Control-Allow-Origin,值就是发起请求的源地址

87.说一下 JSONP 实现原理https://my.oschina.net/aslanjia/blog/903348 https://juejin.im/entry/59a5a194f265da24734447f2
主要原理:
1.Script标签,通过src的方式去加载某一个服务器下的资源
2.用Script标签加载资源是没有跨域问题的,可以加载任何类型的文件

九、设计模式
=============================================================================
88.说一下你熟悉的设计模式
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。

89.简单工厂和抽象工厂有什么区别
简单工厂:工厂类直接实现,一个产品抽象类
工厂方法:一个抽象工厂类,一个产品抽象类,一个工厂类产生一种产品
抽象工厂:一个抽象工厂类,多个产品抽象类。一个工厂类可以产生多种产品

十、Spring/Spring MVC
=============================================================================
90.为什么要使用 spring
第一是使用它的IOC功能,在解耦上达到了配置级别。
第二是使用它对数据库访问事务相关的封装。
第三就是各种其他组件与Spring的融合,在Spring中更加方便快捷的继承其他一些组件。

91.解释一下什么是 aophttps://www.jianshu.com/p/4fca2be4ac25
切面编程,面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术

92.解释一下什么是 ioc
控制反转,可以分解就是“控制”+“反转”。控制指对对象的引用的控制,想象一下面向过程编程的时候,如果A对象要使用B(本文称之为资源对象),按照顺向思维应该怎么做呢,肯定是当A对象用到B的时候去创建B对象,这里是说A控制B,A对象是主动去获取B,这种情况称之为正向。现在是“反转”就是需要反过来,A对象不是主动去获取B,而是被动的等待,等待IOC的容器(你可以理解为提供被调用对象的框架,比如Spring)去获取B的一个实例,注入到A的对象中去,由于这个过程和原来的顺向过程刚好反过来了,所以称之为反向。
一个控制器,在需要的时候才注入

93.spring 有哪些主要模块

94.spring 常用的注入方式有哪些
常用的注入方式主要有三种:构造方法注入,setter注入,基于注解的注入

95.spring 中的 bean 是线程安全的吗
Spring框架并没有对单例的bean进行多线程的封装处理,线程安全问题和并发问题,需要我们开发者自己考虑。
但实际上,大部分的Spring bean并没有可变的状态(比如:service类和dao类),所有在某种程度上来说Spring单例bean是线程安全的。如果bean有多种状态的话(比如:View Model对象),就需要自行考虑线程安全问题。

96.spring 支持几种 bean 的作用域
1.singleton: 当Bean的作用域为singleton的时候,Spring容器中只会存在一个共享的Bean实例,所有对Bean的请求只要id与bean的定义相匹配,则只会返回bean的同一实例。单一实例会被存储在单例缓存中,为Spring的缺省作用域。
2.prototype: 每次对该Bean请求的时候,Spring IoC都会创建一个新的作用域。 对于有状态的Bean应该使用prototype,对于无状态的Bean则使用singleton
3.request: Request作用域针对的是每次的Http请求,Spring容器会根据相关的Bean的,定义来创建一个全新的Bean实例。而且该Bean只在当前request内是有效的。
4.session: 针对http session起作用,Spring容器会根据该Bean的定义来创建一个全新的Bean的实例。而且该Bean只在当前http session内是有效的。
5.global session: 类似标准的http session作用域,不过仅仅在基于portlet的web应用当中才有意义。Portlet规范定义了全局的Session的概念。他被所有构成某个portlet外部应用中的各种不同的portlet所共享。在global session作用域中所定义的bean被限定于全局的portlet session的生命周期范围之内。

97.spring 自动装配 bean 有哪些方式

98.spring 事务实现方式有哪些

99.说一下 spring 的事务隔离
spring 的事务的隔离级别主要有以下五个级别:
1、isolation_default:这个是platformTranscationManger默认的级别,使用的是数据库的默认隔离级别,也就是说我们所用的数据库默认是什么级别,那我们的spring就用什么级别的。大多数的数据库系统的默认事务隔离级别都是:Read committed,而mysql的默认的隔离级是REPEATABLE-READ,我们可以使用 select @@global.tx_isolation 这个命令来查看我们的所使用过的事务的隔离级别。

下面的四个是跟我的数据的级别对应的
3、isolation_read_uncommited (读未提交) 这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
4、isolation_read_commited (读已提交) 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
5、isolation_repeatable_read (可重复读) 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读(现在mysql官网说是可以避免幻读)。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读
6、 isolation_serializable(串行化) 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。

100.说一下 spring mvc 运行流程
SpringMVC执行流程:
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响应用户。

101.spring mvc 有哪些组件
Spring MVC主要包括:
1. 前端控制器组件(DispatcherServlet)
2. 处理器组件(Controller)
3. 处理器映射器组件(HandlerMapping)
4. 处理器适配器组件(HandlerAdapter)
5. 拦截器组件(HandlerInterceptor)
6. 视图解析器组件(ViewResolver)
7. 视图组件(View)
8. 数据转换组件(DataBinder)
9. 消息转换器组件(HttpMessageConverter)

102.@RequestMapping 的作用是什么

103.@Autowired 的作用是什么

十一、Spring Boot/Spring Cloud
=============================================================================
104.什么是 spring boot
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
Spring Boot实现了自动配置,降低了项目搭建的复杂度。众所周知Spring框架需要进行大量的配置,Spring Boot引入自动配置的概念,让项目设置变得很容易。Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box),大部分的Spring Boot应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。Spring Boot只是承载者,辅助你简化项目搭建过程的。如果承载的是WEB项目,使用Spring MVC作为MVC框架,那么工作流程和你上面描述的是完全一样的,因为这部分工作是Spring MVC做的而不是Spring Boot。

105.为什么要用 spring boot

106.spring boot 核心配置文件是什么
用过 Spring Boot 的都知道在 Spring Boot 中有以下两种配置文件
bootstrap (.yml 或者 .properties) 可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。
application (.yml 或者 .properties) 可以用来定义应用级别的。
bootstrap被Spring ApplicationContext的父类加载,这个类先于加载application的ApplicatonContext启动。
boostrap 由父 ApplicationContext 加载,比 applicaton 优先加载,boostrap 里面的属性不能被覆盖。

107.spring boot 配置文件有哪几种类型?它们有什么区别
yml和properties两种文件类型
编写方式不一样,优先级不一样

108.spring boot 有哪些方式可以实现热部署

109.jpa 和 hibernate 有什么区别

110.什么是 spring cloud
Spring Boot,看名字就知道是Spring的引导,就是用于启动Spring的,使得Spring的学习和使用变得快速无痛。不仅适合替换原有的工程结构,更适合微服务开发。Spring Cloud基于Spring Boot,为微服务体系开发中的架构问题,提供了一整套的解决方案——服务注册与发现,服务消费,服务保护与熔断,网关,分布式调用追踪,分布式配置管理等。

111.spring cloud 断路器的作用是什么
在微服务架构中,存在着许许多多的服务单元,若一个服务出现故障,就会因依赖关系形成故障蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构就更加的不稳定。为了解决这样的问题,因此产生了断路器模式,过载保护和容错保护机制

112.spring cloud 的核心组件有哪些
SpringCloud分布式开发五大组件详解
服务发现——Netflix Eureka
客服端负载均衡——Netflix Ribbon
断路器——Netflix Hystrix
服务网关——Netflix Zuul
分布式配置——Spring Cloud Config

 

 

十二、Hibernate
=============================================================================
113.为什么要使用 hibernate
114.什么是 ORM 框架
115.hibernate 中如何在控制台查看打印的 sql 语句
116.hibernate 有几种查询方式
117.hibernate 实体类可以被定义为 final 吗
118.在 hibernate 中使用 Integer 和 int 做映射有什么区别
119.hibernate 是如何工作的
120.get()和 load()的区别
121.说一下 hibernate 的缓存机制
122.hibernate 对象有哪些状态
123.在 hibernate 中 getCurrentSession 和 openSession 的区别是什么
124.hibernate 实体类必须要有无参构造函数吗?为什么

十三、Mybatis
=============================================================================
125.mybatis 中 #{}和 ${}的区别是什么
#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。
$将传入的数据直接显示生成在sql中
#方式能够很大程度防止sql注入

126.mybatis 有几种分页方式
RowBounds:内存分页方式,逻辑分页
PageHelper:数据库分页方式, 物理分页

127.RowBounds 是一次性查询全部结果吗?为什么
是,在DefaultResultSetHandler中,逻辑分页会将所有的结果都查询到,然后根据RowBounds中提供的offset和limit值来获取最后的结果。

128.mybatis 逻辑分页和物理分页的区别是什么
在于内存和数据库

129.mybatis 是否支持延迟加载?延迟加载的原理是什么
在数据与对象进行 mapping 操作时,只有在真正使用到 该对象时,才进行 mapping 操作,以减少数据库查询开销,从而提升系统性能。
但是Lazy Load也有缺点,在 按需加载时会多次连接数据库,同时会增加数据库的压力。所以在实际使用时,会衡量是否使用 延迟加载。
原理: mybatis 会循环处理结果集中返回的每行数据的,在处理之前首先会通过反射调用构造方法来创建 result 对象,结果集中的一行数据最终会映射为一个 result 对象(严格的来说是不对的,结果集中的一行数据在多表连接的情况下可能会映射为多个 result 对象,结果集中的一行数据在多表连接一对多的情况下结果集中的多行数据可能映射一个 result 对象,简单的单表查询结果集中的一行数据映射为一个 result 对象)。

130.说一下 mybatis 的一级缓存和二级缓存
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互相不影响的。也就是他只能作用在同一个sqlSession中,不同的sqlSession中的缓存是互相不能读取的。

二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。二级缓存的作用范围更大。

131.mybatis 和 hibernate 的区别有哪些

132.mybatis 有哪些执行器(Executor)
Mybatis有三种基本的Executor执行器:
SimpleExecutor、ReuseExecutor、BatchExecutor。
SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。

133.mybatis 分页插件的实现原理是什么

134.mybatis 如何编写一个自定义插件
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
Executor (update, query, flushStatements, commit, rollback,
getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 的发行包中的源代码。 假设你想做的不仅仅是监控方法的调用,那么你应该很好的了解正在重写的方法的行为。 因为如果在试图修改或重写已有方法的行为的时候,你很可能在破坏 MyBatis 的核心模块。 这些都是更低层的类和方法,所以使用插件的时候要特别当心。
通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定了想要拦截的方法签名即可。

十四、RabbitMQ
=============================================================================
135.rabbitmq 的使用场景有哪些?
136.rabbitmq 有哪些重要的角色?
137.rabbitmq 有哪些重要的组件?
138.rabbitmq 中 vhost 的作用是什么?
139.rabbitmq 的消息是怎么发送的?
140.rabbitmq 怎么保证消息的稳定性?
141.rabbitmq 怎么避免消息丢失?
142.要保证消息持久化成功的条件有哪些?
143.rabbitmq 持久化有什么缺点?
144.rabbitmq 有几种广播类型?
145.rabbitmq 怎么实现延迟消息队列?
146.rabbitmq 集群有什么用?
147.rabbitmq 节点的类型有哪些?
148.rabbitmq 集群搭建需要注意哪些问题?
149.rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?
150.rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?
151.rabbitmq 对集群节点停止顺序有要求吗?

十五、Kafka
=============================================================================
152.kafka 可以脱离 zookeeper 单独使用吗?为什么?
153.kafka 有几种数据保留的策略?
154.kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?
155.什么情况会导致 kafka 运行变慢?
156.使用 kafka 集群需要注意什么?

十六、Zookeeper
=============================================================================
157.zookeeper 是什么?
158.zookeeper 都有哪些功能?
159.zookeeper 有几种部署模式?
160.zookeeper 怎么保证主从节点的状态同步?
161.集群中为什么要有主节点?
162.集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?
163.说一下 zookeeper 的通知机制?

十七、MySql
=============================================================================
164.数据库的三范式是什么
第一范式(1NF) 强调的是列的原子性,即列不能够再分成其他几列。
第二范式(2NF) 首先是 1NF,另外包含两部分内容,一是表必须有一个主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。
第三范式(3NF) 在1NF基础上,任何非主属性不依赖于其它非主属性[在2NF基础上消除传递依赖]。

165.一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?

表类型若是 MyISAM,则 id 为8;
表类型若是 InnoDB,则 id 为6。
因为InnoDB表只会把自增主键的最大id记录在内存中,所以重启之后会导致最大id丢失。

166.如何获取当前数据库版本

1.select version();
2.mysql -V

167.说一下 ACID 是什么

ACID 一般是指数据库事务的ACID
一个事务一般是指多个操作的集合,比如插入数据库分两段插入,第二次插入错误,第一次插入操作也需要回退
ACID的翻译
1.Atomicity 原子性
2.Consistency 一致性
3.Isolation 隔离性
4.Durability 耐久性
原子性,指的是整个事务是一个独立的单元,要么操作成功,要么操作不成功。
一致性,事务必须要保持和系统处于一致的状态(如果不一致会导致系统其它的方出现bug)。
隔离性,事务是并发控制机制,他们的交错也需要一致性,隔离隐藏,一般通过悲观或者乐观锁实现。
耐久性,一个成功的事务将永久性地改变系统的状态,所以在它结束之前,所有导致状态的变化都记录在一个持久的事务日志中.

 

 

168.char 和 varchar 的区别是什么

首先明确的是,char的长度是不可变的,而varchar的长度是可变的,
char(n):固定长度类型
效率高但是占用空间;适合存储密码的md5值,固定长度的。
varchar(n):长度可变的,存储值是每个值占用的字节加上一个用来记录其长度的字节的长度。
空间考虑用varchar,效率上用char

169.float 和 double 的区别是什么

double 和 float 的区别是double精度高,有效数字16位,float精度7位。但double消耗内存是float的两倍,double的运算速度比float慢得多.

170.mysql 的内连接、左连接、右连接有什么区别

1.内连接只显示两表中有关联的数据
select * from table1 inner join table2 on table1.字段1 = table2.字段2;
2.左连接显示左表所有数据,右表没有对应的数据用NULL补齐,多了的数据删除
select * from table1 left join table2 on table1.字段1 = table2.字段2;
3.右连接显示右表所有数据,左表没有对应的数据用NULL对齐,多了的数据删除
select * from table1 left join table2 on table1.字段1 = table2.字段2;

171.mysql 索引是怎么实现的

索引是用来实现高效查找的。
目前主流的数据库引擎索引都是由 B+ 树实现的,其效率可达到二分法的性能。

mysql索引采用的是B+tree,InnoDB的数据文件本身就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶结点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。

172.怎么验证 mysql 的索引是否满足需求

使用explain查看 SQL是如何执行查询语句的,从而分析索引是否满足需求。
语法: explain select * from table where type = 1。

173.说一下数据库的事务隔离

MySQL的事务隔离是在MySQL.ini 配置文件里添加的,在文件最后添加: transaction-isolation = REPEATABLE-READ
可用配置:
READ-UNCOMMITTED:未提交读,最低隔离级别,事务未提交前,就可被其他事务读取(会出现幻读,脏读,不可重复读)
READ-COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读,不可重复读)
REPEATABLE-READ:可重复读,默认级别,保证多次读取同一个数据时,其值和事务开始时内容一致,禁止读取到别的事务没提交的数据(会造成幻读)
SERIALIZABLE:序列化,代价最高最可靠的隔离级别,能防止脏读,不可重复读,幻读。
脏读:表示一个事务能够读取另一个事务中还未提交的数据。
不可重复读:指在一个事务内,多次读同一数据。
幻读:指同一事务内多次查询返回的结果集不同。

174.说一下 mysql 常用的引擎

InnoDB:
此引擎提供了对数据 ACID 事务的支持,且提供行级锁和外键的约束,设计目标就是处理大数据容量的数据库系统。
MySQL运行时,InnoDB会在内存中建立缓冲池,用于缓冲数据和索引,但是不支持全文搜索,且启动慢,不会保存表行数,当进行 select count(*) from table 指令时,需进行扫描全表。
由于锁的粒度小,写操作不会锁定全表,所以在并发度较高的场景下使用会提升效率。

MyIASM:
MySQL的默认引擎,但不提供事务支持,也不支持行级锁和外键。
当执行插入和更新语句时,即执行写操作时需要锁定这个表,导致效率降低。
但它保存了表的行数,当进行那条语句时可以直接读取已经保存的值而不用扫描全表。
当表的读操作远大于写操作是,并且不需要事务支持的,可用MyISAM。

175.说一下 mysql 的行锁和表锁

MyISAM只支持表锁,InnoDB支持表锁和行锁,默认为行锁。
表级锁:开销小,加锁快,不会出现死锁。锁定力度大,发生锁冲突概率高,并发量最低。
行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突概率小,并发度最高。

176.说一下乐观锁和悲观锁

乐观锁:每次去拿数据都认为别人不会修改,所以不上锁,但在提交更新时会判断在此期间是否有人更新数据。
悲观锁:每次去拿数据都认为别人修改了,所以每次都上锁,这样别人拿回被阻止,知道此锁被释放。

177.mysql 问题排查都有哪些手段

使用 show processlist 命令查看当前所有连接信息。
使用 explain 命令查询SQL语句执行计划。
开启慢查询日志,查看慢查询的SQL。

178.如何做 mysql 的性能优化

为搜索字段创建索引
避免使用select*,列出需要查询字段
垂直分割分表
选择正确的存储引擎

 

十八、Redis   https://juejin.im/post/5cb13b4d6fb9a0687b7dd0bd
=============================================================================
179.redis 是什么?都有哪些使用场景?
180.redis 有哪些功能?
181.redis 和 memecache 有什么区别?
182.redis 为什么是单线程的?
183.什么是缓存穿透?怎么解决?
184.redis 支持的数据类型有哪些?
185.redis 支持的 java 客户端都有哪些?
186.jedis 和 redisson 有哪些区别?
187.怎么保证缓存和数据库数据的一致性?
188.redis 持久化有几种方式?
189.redis 怎么实现分布式锁?
190.redis 分布式锁有什么缺陷?
191.redis 如何做内存优化?
192.redis 淘汰策略有哪些?
193.redis 常见的性能问题有哪些?该如何解决?

十九、JVM 
=============================================================================
194.说一下 jvm 的主要组成部分?及其作用? https://juejin.im/post/5cad272a5188254eb942fabe
1)程序计数器 几乎不占内存,用于取下一条指令
2)堆,所有通过new创建的对象的内存都在堆中分配,堆被划分为新生代和老年代。
3)栈,每个线程执行每个方法的时候都会在栈中申请一个栈帧,每个栈帧包括局部变量区和操作数栈,用于存放此次方法调用过程中的临时变量、参数和中间结果
4)本地方法栈 用于支持native方法的执行,存储每个native方法调用的状态
5)方法区 存放要加载的类信息、静态变量、final类型常量、属性和方法信息,jvm用永久代来存放方法区

195.说一下 jvm 运行时数据区
1. 单线程数据区(非共享) 每个线程都有自己独立的数据区,包括 PC(程序计数器),JVM(方法)栈,以及本地方法栈. 当创建新线程时,这些数据区域将会一并创建.
程序计数器: 英文名字是 Program Counter Register,简称PC, 用于记录每个线程执行到哪个地方了(可以认为程序是指令的序列,PC记录着下一条(或本条)应该执行的指令的地址).
JVM方法栈: 包含如下面的图所示的一些栈帧(frame).
本地方法栈: 英文为 Native Method Stack,顾名思义,适用于供 native方法使用的内存空间,本地方法(native method)指不用Java语言开发的方法,如 C,C++,PB等编译型语言所开发的动态链接库(中的方法).

2. 所有线程共享数据区 堆内存 和 方法区 是所有线程共享的数据区.
堆内存: 英文名称 Heap,是Java编程最频繁使用的内存区域. 其中存储着 数组和对象,当 JVM启动时即创建此内存区域, 垃圾回收主要是指堆内存的回收。
方法区: Method Area,存储了 运行时常量池,类结构信息(field and method data) 以及 方法,构造器的代码.
运行时常量池: Runtime Constant Pool, 每一个类或者接口,在其编译后生成的 .class文件中,有一个部分叫做 常量表(constant_pool_table),JVM将class文件加载以后,就解析常量表的内容到运行时常量池. 包括编译时方法中就明确可知的数字值,String值, 以及必须在运行时解析的属性域引用(field reference).

196.说一下堆栈的区别
栈内存:栈内存首先是一片内存区域,存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。

堆内存:存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中(这句话还是不严谨,JVM中的逃逸分析就打破了这一点,详情请看链接:https://mp.csdn.net/postedit/81214178),堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。堆里的实体虽然不会被释放,但是会被当成垃圾,Java有垃圾回收机制不定时的收取。

堆与栈的区别很明显:
1.栈内存存储的是局部变量而堆内存存储的是实体;
2.栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;
3.栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。

197.队列和栈是什么?有什么区别
栈:是限制在表的一端进行插入和删除运算的线性表。栈又称后进先出
队列:也是一种运算受限的线性表。它只允许在标的一端进行插入,而在另一端进行删除。队列亦称:先进先出

198.什么是双亲委派模型
简单说就是当类加载器(Class-Loader)试图加载某个类型的时候,除非父加载器找不到相应类型,否则尽量将这个任务代理给当前加载器的父加载器去做。使用委派模型的目的是避免重复加载 Java 类型。
双亲委派模型工作过程是:如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。
双亲委派模型的原理很简单,实现也简单。每次通过先委托父类加载器加载,当父类加载器无法加载时,再自己加载。其实ClassLoader类默认的loadClass方法已经帮我们写好了,我们无需去写。

199.说一下类加载的执行过程
一个类的生命周期包括加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using) 和 卸载(Unloading)七个阶段。

200.怎么判断对象是否可以被回收https://blog.csdn.net/u012233285/article/details/61925319
jvm要做垃圾回收时,首先要判断一个对象是否还有可能被使用。那么如何判断一个对象是否还有可能被用到?
如果我们的程序无法再引用到该对象,那么这个对象就肯定可以被回收,这个状态称为不可达。当对象不可达,该对象就可以作为回收对象被垃圾回收器回收。

201.java 中都有哪些引用类型
强引用( Final Reference) 就是指在程序代码中普遍存在的,类似Object obj = new Object()这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。
软引用(Soft Reference) 是用来描述一些还有用但并非必须的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。
弱引用(Weak Reference) 用来描述非必须的对象,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发送之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。一旦一个弱引用对象被垃圾回收器回收,便会加入到一个注册引用队列中。

虚引用(Phantom Reference) 虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个持有虚引用的对象,和没有引用几乎是一样的,随时都有可能被垃圾回收器回收。当试图通过虚引用的get()方法取得强引用时,总是会失败。并且,虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。

202.说一下 jvm 有哪些垃圾回收算法
1.引用计数器算法: 引用计数器算法是给每个对象设置一个计数器,当有地方引用这个对象的时候,计数器+1,当引用失效的时候,计数器-1,当计数器为0的时候,JVM就认为对象不再被使用,是“垃圾”了。
引用计数器实现简单,效率高;但是不能解决循环引用问问题(A对象引用B对象,B对象又引用A对象,但是A,B对象已不被任何其他对象引用),同时每次计数器的增加和减少都带来了很多额外的开销,所以在JDK1.1之后,这个算法已经不再使用了。
2.根搜索方法: 根搜索方法是通过一些“GCRoots”对象作为起点,从这些节点开始往下搜索,搜索通过的路径成为引用链(ReferenceChain),当一个对象没有被GCRoots的引用链连接的时候,说明这个对象是不可用的。

203.说一下 jvm 有哪些垃圾回收器? https://zackku.com/jvm-gc-collector/
Serial收集器 串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。新生代、老年代使用串行回收;新生代复制算法、老年代标记-压缩;垃圾收集的过程中会Stop The World(服务暂停)
Parallel收集器 Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量。可以通过参数来打开自适应调节策略,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量;也可以通过参数控制GC的时间不大于多少毫秒或者比例;
Parallel Old 收集器 Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。这个收集器是在JDK 1.6中才开始提供
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用都集中在互联网站或B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。
G1收集器 G1是目前技术发展的最前沿成果之一,HotSpot开发团队赋予它的使命是未来可以替换掉JDK1.5中发布的CMS收集器。

204.详细介绍一下 CMS 垃圾回收器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用都集中在互联网站或B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。
CMS收集器是基于“标记-清除”算法实现的,它的运作过程相对于前面几种收集器来说要更复杂一些,整个过程分为4个步骤,包括:
初始标记(CMS initial mark)
并发标记(CMS concurrent mark)
重新标记(CMS remark)
并发清除(CMS concurrent sweep)
其中初始标记、重新标记这两个步骤仍然需要“Stop The World”。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。
由于整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,所以总体上来说,CMS收集器的内存回收过程是与用户线程一起并发地执行。
优点: 并发收集、低停顿
缺点: 产生大量空间碎片、并发阶段会降低吞吐量

205.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别

根据垃圾回收对象的特性,不同阶段最优的方式是使用合适的算法用于本阶段的垃圾回收,分代算法即是基于这种思想,它将内存区间根据对象的特点分成几块,根据每块内存区间的特点,使用不同的回收算法,以提高垃圾回收的效率。以 Hot Spot 虚拟机为例,它将所有的新建对象都放入称为年轻代的内存区域,年轻代的特点是对象会很快回收,因此,在年轻代就选择效率较高的复制算法。当一个对象经过几次回收后依然存活,对象就会被放入称为老生代的内存空间。在老生代中,几乎所有的对象都是经过几次垃圾回收后依然得以幸存的。因此,可以认为这些对象在一段时期内,甚至在应用程序的整个生命周期中,将是常驻内存的。如果依然使用复制算法回收老生代,将需要复制大量对象。再加上老生代的回收性价比也要低于新生代,因此这种做法也是不可取的。根据分代的思想,可以对老年代的回收使用与新生代不同的标记-压缩算法,以提高垃圾回收效率。

206.简述分代垃圾回收器是怎么工作的? https://blog.csdn.net/J080624/article/details/85922914 https://blog.csdn.net/Java_Grass/article/details/62886965

虚拟机中的共划分为三个代:年轻代(Young Generation)、年老代(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系不大。年轻代和年老代的划分是对垃圾收集影响比较大的。

① 年轻代
所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个Survivor区(一般而言)。大部分对象在Eden区中生成。
当Eden空间不足时,触发Minor GC,还存活的对象将被转移到Survivor区(两个中的一个);当这个Survivor区满时,此区的存活对象将被转移到另外一个Survivor区;当这个Survivor区也满了的时候,从第一个Survivor区转移过来的并且此时还存活的对象,将被转移到“年老代(Tenured)”。
需要注意,Survivor的两个区是对称的,没先后关系。所以同一个区中可能同时存在从Eden复制过来对象和从前一个Survivor复制过来的对象。而复制到年老区的只有从第一个Survivor区过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。

② 年老代
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

③ 持久代
持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=<N>进行设置(jdk1.8后被元空间取代)。

 

207.说一下 jvm 调优的工具
jvm监控分析工具一般分为两类,一种是jdk自带的工具,一种是第三方的分析工具。
jdk自带工具一般在jdk bin目录下面,以exe的形式直接点击就可以使用,其中包含分析工具已经很强大,几乎涉及了方方面面,但是我们最常使用的只有两款:jconsole.exe和jvisualvm.exe;
第三方的分析工具有很多,各自的侧重点不同,比较有代表性的:MAT(Memory Analyzer Tool)、GChisto等。

208.常用的 jvm 调优的参数都有哪些
-Xmx:最大JVM可用内存, 例:-Xmx4g
-Xms:最小JVM可用内存, 例:Xms4g
-Xmn:年轻代内存大小,例:-Xmn2560m
-XX:PermSize:永久代内存大小,该值太大会导致fullGC时间过长,太小将增加fullGC频率,例:-XX:PermSize=128m
-Xss:线程栈大小,太大将导致JVM可建的线程数量减少,例:-Xss256k
-XX:+DisableExplicitGC:禁止手动fullGC,如果配置,则System.gc()将无效,比如在为DirectByteBuffer分配空间过程中发现直接内存不足时会显式调用System.gc()
-XX:+UseConcMarkSweepGC:一般PermGen是不会被GC,如果希望PermGen永久代也能被GC,则需要配置该参数
-XX:+CMSParallelRemarkEnabled:GC进行时标记可回收对象时可以并行remark-XX:+UseCMSCompactAtFullCollection 表示在fullGC之后进行压缩,CMS默认不压缩空间
-XX:LargePageSizeInBytes:为java堆内存设置内存页大小,例:-XX:LargePageSizeInBytes=128m
-XX:+UseFastAccessorMethods:对原始类型进行快速优化
-XX:+UseCMSInitiatingOccupancyOnly:关闭预期开始的晋升率的统计
-XX:CMSInitiatingOccupancyFraction:使用cms作为垃圾回收,并设置GC百分比,例:-XX:CMSInitiatingOccupancyFraction=70(使用70%后开始CMS收集)
-XX:+PrintGCDetails:打印GC的详细信息
-XX:+PrintGCDateStamps:打印GC的时间戳
-Xloggc:指定GC文件路径