Java基础面试题
ArrayList、CopyOnWrityArrayList、HashMap等常见问题
Java基础面试题
请谈谈你对Java中 String, StringBuilder 和 StringBuffer 的理解,它们之间有什么区别?
String是java中的字符串封装类型,其底层是char数组,他的长度不可变,任何对字符串进行修改的操作,都是重新在堆内存中创建了一个新的String对象。
StringBuilder和StringBuffer都继承了 AbstractStringBuilder ,其底层也是维护一个char数组,但他们是可变的字符串操作对象,对于动态的字符串操作,这两个性能相对String较好,因为String在大量循环字符串拼接的场景,会产生大量的垃圾对象。
StringBuilder存在线程安全问题,并发操作是,可能出现某一操作被下一操作覆盖等问题。
StringBuffer是线程安全的,在操作时会添加synchronized,并发请求操作时,是同步去进行的,但也正因为加了锁,所以他的性能略低于StringBuilder。
说一下ArrayList和LinkedList的区别
ArrayList和LinkedList都是用来存储数据列表的。
但是ArrayList的底层数据结构是数组,LinkedList是双向链表,这也就从基因上决定了,ArrayList适合做查询操作,LinkedList适合做元素经常变动的操作。
数组可以直接通过索引下标获取到指定的元素,而链表需要一个元素一个元素去遍历才能找到指定元素(除非是找第一个或最后一个元素)。
数组元素有变动,后面跟着的元素都需要随之跟着移动重排,而链表只需要将本节点移除,然后将上一个元素重新指向下一个元素,下一个元素指向上一个元素即可,其他元素节点无需变动(中间新增插入同理,将上一个元素指向新元素,新元素指向下一个元素即可)。
ArrayList每次新增元素操作都需要去判断是否需要扩容,而LinkedList不存在扩容这一说法,直接新增元素节点就完事了。
CopyOnWrityArrayList的底层原理是怎么样的
写时复制;
写操作有synchronized,是复制旧数组到新数组,然后新增元素最加到新数组,最后替换内存地址;
读操作是读的旧数组;
CopyOnWrityArrayList是线程安全的List,最核心的特点是写时复制。
在新加入一个元素时,CopyOnWrityArrayList会给add这个操作方法先套上synchronized,所以他是线程安全的,其他线程调用add方法都需要阻塞等待。执行add方法时,CopyOnWrityArrayList会将当前数组的元素全部复制到一个新的数组里,新数组长度加一,然后将新增的元素插入到新数组里,最后再将新数组的内存地址替换过去。在次期间,所有的读操作,都还读的是旧的数组,不会受到新增操作加锁的影响。
这种机制在写操作频繁时会有较大的内存开销和性能问题,因为每次写都要复制整个数组,所以他比较适合读多写少的场景。
