CopyOnWriteArrayList的底层原理是怎样的
1.首先CopyOnWriteArraylist内部也是用过数组来实现的,在向CopyOnWriteArrayLlist添加元素时,会复制一个新的数组
写操作在新数组上进行,读操作在原数组上进行
2.并且,写操作会加锁,防止出现并发写入丢失数据的问题
3.写操作结束之后会把原数组指向新数组
4.CopyOnWriteArrayList允许在写操作时来读取数据,大大提高了读的性能,因此适合读多写少的应用场景,但是CopyOnWriteArrayList会比较占内存,同时可能读到的数据不是实时最新的数据,所以不适合实时性要求很高的场景
final
修饰类:表示类不可被继承
修饰方法:表示方法不可被子类覆盖,但是可以重载
修饰变量:表示变量—旦被赋值就不可以更改它的值。
修饰的变量是基本数据类型的话,不可以改变他的值。而修饰引用类型的话不可以改变它的引用,但是可以改变它引用对象的值。
(1)如果final修饰的是类变量,只能在静态初始化块中指定初始值或者声明该类变量时指定初始值。
如果final修饰的是成员变量,可以在非静态初始化块、声明该变量或者构造器中执行初始值。
(2)修饰局部变量
使用前一定要赋值(可以先分配空间再赋值),且复制完无法修改。
HashMap和HashTable有什么区别?其底层实现是什么?
区别︰
(1) HashMap方法没有synchronized修饰,线程非安全,HashTable线程安全;
(2) HashMap允许key和value为null,而HashTable不允许
⒉.底层实现:数组+链表实现
-
jdk8开始链表高度到8、数组长度超过64,链表转变为红黑树,元素以内部类Node节点存在·计算key的hash值,二次hash然后对数组长度取模,对应到数组下标,
-
如果没有产生hash冲突(下标位置没有元素),则直接创建Node存入数组,
-
如果产生hash冲突,先进行equal比较,相同则取代该元素,不同,则判断链表高度插入链表,链表高度达到8,并且数组长度到64则转变为红黑树,长度低于6则将红黑树转回链表
-
key为null,存在下标0的位置
Java中的异常体系
Java中的所有异常都来自顶级父类Throwable。
Throwable下有两个子类Exception和Errqr。
- Error是程序无法处理的错误,一旦出现这个错误,则程序将被迫停止运行。
- Exception不会导致程序停止,又分为两个部分RunTimeException运行时异常和CheckedException检查异常。RunTimeException常常发生在程序运行过程中,会导致程序当前线程执行失败。CheckedException常常发生在程序编译过程中,会导致程序编译不通过。
List和Set的区别
- List:有序,按对象进入的顺序保存对象,可重复,允许多个Null元素对象,可以使用lterator取出所有元素,在逐—遍历,还可以使用get(int index)获取指定下表的元素
- Set:无序,不可重复,最多允许有一个Null元素对象,取元素时只能用lterator接口取得所有元素,在逐一遍历各个元素
Jdk1.7到Jdk1.8 HashMap发生了什么变化(底层)?
-
1.7中底层是数组+链表,1.8中底层是数组+链表+红黑树,加红黑树的目的是提高HashMap插入和查询整体效率
-
1.7中链表插入使用的是头插法,1.8中链表插入使用的是尾插法,因为1.8中插入key和lvalue时需要判断链表元素个数,所以需要遍历俳表统计铤表元素个数,所以正好就直接使用尾插法
-
1.7中哈希算法比较复杂,存在各种右移与异或运算,1.8中进行了简化,因为负载的哈希算法的目的就是提高散列性,来提供HshMap的整体效率,而1.8中新增了红黑树,所以可以适当的简化哈希算法,节省CPU资源
Jdk1.7到Jdk1.8 java虚拟机发生了什么变化?
1.7中存在永久代,1.8中没有永久代,替换它的是元空间,元空间所占的内存不是在虚拟机内部,而是本地内存空间,这么做的原因是,不管是永久代还是元空间,他们都是方法区的具体实现,之所以元空间所占的内存改成本地内存,官方的说法是为了和Rockit统一,不过额外还有一些原因,比如方法区所存储的类信息通常是比较难确定的,所以对于方法区的大小是比较难指定的,太小了容易出现方法区溢出,太大了又会占用了太多虚拟机的内存空间,而转移到本地内存后则不会影响虚拟机所占用的内存