1、String/StringBuffer/StringBuilder 区别
string:值不可变,每次操作生成新的对象,底层基于char数组且有final修饰,1.8后使用byte
数组
StringBuffer:值可变,线程安全,多线程操作字符串对象。
StringBuilder:值可变,线程不安全,单线程操作字符串,速度快。
2、String为什么不可变,StringBuffer为什么可变
String:底层使用char数组,且有private、final修饰。
StringBuffer:底层是char数组,没有final修饰,初始容量为16,存满后会调用system的
arraycopy方法进行扩容。
3、StringBuffer为什么线程安全,StringBuilder为什么不安全
StringBuffer安全的主要原因是在使用的append方法上添加了synchronized锁。
他们都继承了AbstractStringBuilder,这个类中有两个重要的变量,一个是count字符串数组长度,一个是存储字符的char数组。在多线程同时操作字符串时,count会因为没有加锁而漏加,导致字符串长度要小于实际长度。
4、ArrayList和LinkedList的区别
ArrayList:基于数组,内存分配要求有连续性,查询时是根据下标读取,速度快,增删涉及位移操作,速度相对慢。
LinkedList:基于链表,内存分配不要求连续性,查询需要从头到尾挨个查询,速度慢,增删不涉及位移操作,只需更改前后节点指向,速度快。
5、ArrayList和Vector的区别
ArrayList:基于动态数组,默认创建空数组。
第一次添加元素扩容为10,后为1.5倍扩容。
多线程不安全,适合单线程操作,效率高。
Vector:基于动态数组,默认创建容量为10的数组
扩充算法:增量为0,原大小乘2
增量不为0,原大小乘2加增量
加了锁线程安全,适合多线程操作,效率低。
6、面向对象的特征
抽象:抽象是将一类对象的共同特征总结出构造类的过程,包括行为抽象和数据抽象,抽象
只关注对象的属性和行为,不关注行为的细节
封装:把过程和数据包围起来,对数据的访问只能通过已定义的方式。使模块有较好的独立
性、修改程序方便。
继承:新类从现有类中派生。新类继承父类的特性。
多态:对象的多种形态,编译和运行时类型不一样。目的:屏蔽子类差异
7、接口和抽象类
8、==和equals的区别
==:对于基本数据类型对比存储的值,对于引用数据类型对比的是地址。
equals:对比两个对象存储的值。区分大小写。
9、int和integer的区别
int:基本数据类型,默认为0,存储的数值,无需实例化。
integer:引用数据类型,默认null,存储对象的地址,需要实例化。
10、Java集合体系
11、HashMap和HashTable的区别
1、继承的父类不一样,HasMap为AbstractMap类,HashTable为dictionary。
2、HashMap的key和value支持null,key为null只能由一个,HashTable都不能为null。
3、HashMap线程不安全,多线程可能会死锁、死循环。HashTable在每个方法中都加
synchronized锁。
4、HashMap初始容量为16,扩容算法为2n。HashTable初始11,扩容为2n+1.
12、那种Map线程安全和性能都可以兼得。
ConcurrentHashMap。它使用了分段锁技术,将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一段数据时,其他段的数据可以被其他线程访问。
13、ConcurrentHashMap的理解
1.7:由Segment数组和HashEntry组成,还是数组加链表
1.8:CAS和Synchronized组成,存放数据的HashEntry改为了Node节点,他的val和next都使用了Volatile修饰保证可见性,
8在7的数据结构上做了很大改动,采用红黑树可以保证查询的效率,取消了ReentrantLock改为了Synchronized。因为8后对synchronized做了很大的优化。
14、数据结构有哪些
集合:结构中的元素除了同属一个集合,没有其他联系
线性:结构中元素存在一对一关系
树形:结构中元素存在一对多关系
图形:结构中元素存在多对多关系
顺序存储结构:内存中是一段连续的存储单元存储数据
链接存储结构:内存中是不连续的存储单元,
数据索引存储结构:建立附加的索引来标识节点地址,通过索引,可以很快检索数据
数据散列存储结构:将数据元素的存储位置与关键字间建立确定的对应关系,加快查找
15、数组和链表在内存中的存储结构有什么区别
数组:内存中是一块连续的区域。
数组需要预留空间,在使用前要申请占内存大小
插入、删除数据性能较低
随机读取效率高
不利于扩展,空间不够需要重新定义数据。
链表:内存中随机存放,不要求连续性。
每个数据保存下一个的数据内存地址,可以通过一个元素查找它的下一个元素。
增删数据性能高
查询效率低
不指定大小,扩展方便。
16、散列存储(Hash存储) , 什么是Hash冲突 , 有什么解决方案
理解:将数据元素的存储位置与关键字之间建立确定关系的查找技术。通过把关键字的值
去访问对应的数据值的一个存储结构。
Hash冲突:两个不同的值计算出了相同的Hash,即两个数据在Hash表中计算出同一个下标。
解决方案:链地址法:把Hash碰撞的元素指向一个链表。
开放寻址:冲突的key在进行Hash,计算出另一个Hash,直到不一样。
再散列法:冲突后使用不同的Hash函数。
建立公共溢表:把Hash表分为基本表和溢出表,把冲突的元素放溢出表
17、list集合如何实现根据数字排序。
1、让list的泛型类继承Comparable接口,覆写compareTo方法,方法中自定义根据数字大小比较
2、调用Collections的sort方法,传入一个比较器,覆写compare方法,方法中自定义根据年龄比较算法。
18、HashMap底层用到了那些数据结构。
1.7前:数组、链表
1.8及后;数组、链表、红黑树
19、为什么HashMap使用了链表结构
HashMap在添加元素时,将key进行hash计算,结果模与数组长度得到一个下标,再把元素添加进去。这样可能会产生hash碰撞,不同key计算出相同的Hash值,因此它采用链表,将产生碰撞的值挂载到链表中。
20、为什么要用到红黑树
1.7使用数组加链表会造成一个链表的元素过多,通过key值一次查找的效率较低。
1.8后引入红黑树,如果链表长度超过8,链表就会转换为红黑树,从而减少查询时间。
21、链表和红黑树转换条件
链表转红黑树:链表长度达到8、数组长度达到64
红黑树转链表:树节点小于等于6.
8:泊松分布,根据概率统计选择。
6:防止链表和树频繁转换。
22、HashMap在什么情况下扩容。如何扩容
初始容量为16,负载因子0.75。当数组元素大于12时,会扩容。
0.75:负载因子过小容易浪费空间,过大容易造成更多的hash碰撞,产生更多的链表和树。
成倍扩容:保证数组的长度是2的整数次幂。
23、HashMap如何put一个元素
首先对key做hash运算,计算出下标。
如果么有产生碰撞直接放在数组索引位置。
如果产生碰撞,链接的形式存放在对应下标后面。
如果该链表过长,就把链表转换成红黑树。
如果节点已存在该相同的值,就把新的值替换成旧的值
如果超过数组的要求扩容的值,就对数组进行2倍扩容
24、HashMap是如何get一个元素
对key做hash运算,计算出下标
在数组对应位置的下标进行比较,如果hash值相等就返回此位置的值,没有则返回null
如果不相等代表hash冲突
如果是链表则从头便利,比较链表中节点的key和传入的key是否相等。
如果是红黑树,则从树中的节点去对比key
25、HashMap冲突
两个不同的值计算出了相同的Hash,即两个数据在Hash表中计算出同一个下标。
26、除了链表如何解决HashMap冲突
1、开放寻址:冲突的key在进行hash,计算出另一个hash直到不一样。
2、再散列法:冲突后使用不同的hash函数。
3、建立公共溢表:把hash表分为基本表和溢出表,把冲突的元素放在溢出表。
27、HashMap死循环
HashMap在扩容数组的时候,会将旧数据迁徙到新数组中,这个操作会将原来链表中的数据颠倒,比如a->b->null,转换成b->a->null。这个过程单线程是没有问题的,但是在多线程环境,就可能会出现a->b->a->b....,这就是死循环
在JDK1.8后,做了改进保证了转换后链表顺序一致,死循环问题得到了解决。但还是会出现高并发时数据丢失的问题,因此在多线程情况下还是建议使用ConcurrentHashMap来保证线程安全问题。
28、LinkedHashMap与HashMap的关系
LinkedHashMap继承HashMap,是居于HashMap和双向链表实现的。
LinkedHashMap是有序的,HashMap是无序的。
LinkedHashMap的双向链表是为了维护Map的迭代顺序,让迭代顺序和插入顺序一致。
29、HashSet和HashMap是什么关系
HashSet实现了set接口,只存储对象,HashMap实现了Map接口,存储的使键值对。
HashSet底层使用HashMap实现存储,依靠HashMap的key进行存储,value默认为object对象,所以HashSet不允许重复值,判断标准为比较HashCode
30、TreeSet底层用到了什么结构来实现
TreeSet底层是TreeMap,添加数据存入Map的key的位置,而value的位置固定是Present。
它里面的元素是有序不重复的,因为TreeMap中的key是有序不重复的。
31、TreeSet默认是如何排序的?如何自定义排序规则?
默认:实现了SortedSet接口,使得TreeSet具有排序功能,正序排序
自定义:通过比较器排序,实现Comparator复写compare方法