== 和 equals的区别
==是对比的是栈中的值,基本类型比的是变量值,引用类型比的是堆中引用的地址
equals比的是对应类定义的逻辑,比如:Object的equals就是==,String中equals比的是字符串内容,也可以自定义equals方法写入自己的比较逻辑
final的作用
修饰类:不能被继承
修饰方法:不能重写,但能重载
修饰变量:一旦赋值,不能更改
为什么局部内部类和匿名内部类只能访问局部final变量
待补充
String,StringBuilder,StringBuffer区别和场景
String是final修饰的,不可改变,每次更改会产生新String对象
StringBuffer为synchronized修饰,线程安全,StringBuilder线程不安全
性能 StringBuilder > StringBuffer > String
场景:没什么长度变化时用String即可,有场景变动优先使用StringBuilder,多线程使用共享变量时用StringBuffer
重载和重写的区别
重载:同一类中,方法名相同,入参类型或数量不同,不包括不同返回值
重写:又叫覆盖,是子类中重写了重名但不重载的方法,如果父类是private或final修饰则不能重写
接口和抽象类的区别
抽象只能单继承,接口能多实现
抽象类可以有普通方法和抽象方法,接口只能有抽象方法
抽象类的成员变量类型不限,接口的成员变量只能是static final修饰(不写默认有)
从设计初衷看:
接口设计目的是对类的行为进行底线约束,实现接口必须至少要实现接口中的方法
抽象类设计目的是代码复用,不同类有相同的共性时,抽取放在抽象类里面
从逻辑上来说,先有接口,再有实现类,最后才有抽象类
java中的异常体系
java中的所有 都来自顶级Throwable,下面2个子类,Exception和Error
Exception分为RunTimeException和CheckedException,运行时异常导致当前线程执行失败,编译异常会直接编译不通过
Error是程序不处理的错误,一旦出现,程序被迫中止
List和Set
List有索引,有序,可以用索引和迭代器获取元素
Set无索引,无序不重复,只能用迭代器获取元素
hashCode和equals
hashCode是Object的方法,他的作用是获取哈希码(散列码),int类型,指向哈希表的索引位置,哈希表是键值对儿,快速获取对应的值
举个例子,HashSet判断存入的元素是否重复,则先根据哈希码找到元素判断是否存在,如果存在了,则调用equals判断是否真的相等,若相等,就不让其加入成功,若不等则散列到其它位置。好处是大幅减少equals的比较次数。
所以:
对象相等,hashCode一定相等
对象相等,equals都为true
相同hashCode,值不一定等
equals被重写,hashCode也要重写
默认的hashCode如果不重写永远不会相等
ArrayList和LinkedList区别
ArrayList基于动态数组,占用连续内存
有扩容机制:因为数组长度固定,所以需重新开辟一片连续内存,将原来的元素复制过来。默认是0,加一个变10,然后原来的基础上x1.5向下取整,比如10,15,22
增删慢:如果要在中间插入元素还要移动元素,但若是尾部插入且不需要扩容情况下也是很快的
LinkedList基于链表,内存分散,适合做增删,不适合查改
遍历要用iterator,一定不能用元素索引,比如for循环和indexOf,用索引都要遍历,性能消耗大
CocurrentHashMap原理
JDK 8:
数据结构:synchronized + CAS + Node + 红黑树
Node的val和next都用volatile修饰,保证可见性
查找,替换,赋值操作都是用CAS乐观锁,效率高
synchronized锁:扩容,哈希冲突使用,锁链表的head节点,不影响其它元素的读写,锁粒度更细,效率更高,扩容时,阻塞所有的读写操作、并发扩容
读操作无锁:
Node的val和next使用volatile修饰,读写线程对该变量互相可见
数组用volatile修饰,保证扩容时被读线程感知