Javas细节
Contents
java Queue
- add/offer
- add:向队列末尾添加一个元素,若队列已满,则抛出异常
- offer:不会抛异常,返回false。
- remove/poll
- remove:移除队列队头元素,若队列为空,则抛出异常
- poll:不抛出异常,返回null
- element/peek
- element:查询队列头部元素,若队列为空,则抛出异常
- peek:不会抛出异常,返回null
形参/实参
- 用来接收调用该方法时传递的参数。只有在被调用的时候才分配内存空间,一旦调用结束,就释放内存空间。因此仅仅在方法内有效。
- 传递给被调用方法的值,预先创建并赋予确定值。
- 传值调用:传值调用中传递的参数为基本数据类型,参数视为形参。
- 传引用调用:传引用调用中,如果传递的参数是引用数据类型,参数视为实参。在调用的过程中,将实参的地址传递给了形参,形参上的改变都发生在实参上。
泛型
- 参数化类型,也就是将类型参数化,可以通过传递参数来设置变量类型。
- ArrayList 默认是Object类型的,所以只要是Object的子类,什么都可以放
- 为什么ArrayList的传入参数类型不是Object,而是一个泛型?可以规范传入参数类型,只允许传入某种类型,从而在编译期就发现问题,不要将问题遗留到运行期。
- 泛型只有在编译期才有效
- 三种用法
- 泛型类:在实例化类的时候指明泛型类型
- 泛型接口
- 泛型方法:在调用方法的时候指明泛型类型
- https://www.cnblogs.com/coprince/p/8603492.html
|
|
exception、error的区别
- 两者父类都是 throwable类
- error一般是指与JVM相关的问题,比如系统崩溃、内存不足、栈溢出等,这类问题导致的应用中断仅靠程序本身无法恢复和预防
- Exception表示程序可以处理的异常,可以捕获且可能恢复。
ConcurrentHashMap 的 get 方法为什么不需要加锁
- 获取 hash 桶的根节点通过
tabAt
来完成,线程安全 - 遍历的时候用到了节点的 next 属性,被 volative 关键字修饰,线程间可见,线程安全
- 获取节点的 value 时,节点的 value 值也是被 volatile 修饰,线程间可见,线程安全。
- 如果正在扩容中,会根据 ForwardingNode get到新表中的内容。
ConcurrentHashMap 的 putVal 是如何做的?
- 根据 hashcode 利用 tabAt 函数得到插入位置的下标
- 判读数组中此处元素是否为 null,如果为 null,直接采用 CAS 进行插入操作即可。
- 如果不为空并且发现正在进行 rehash,此线程就会帮忙 rehash 操作。
- 如果部位空,且没在进行 rehash,会用 synchronized 关键字锁住头节点,进行插入操作(尾插法)
HashMap的扰动函数的作用?
- 主要作用就是使哈希更加均匀,避免过多的哈希冲突
- 由于哈希过程相当于对hashmap的 length 取模(length 必须是2的n次方,这样和
length-1
与操作就等同于取模操作了),会使得 hashcode 的高位信息丢失,导致哈希不均匀。 - 扰动函数就是将 hashcode 的高位与其低位进行异或操作,这样低位就既包含了整个 hashcode 的信息。
- 对经过扰动函数处理之后的 hashcode 再进行取模,获得的结果就更均匀了。
HashMap 的 rehash 与 redis 的 rehash 有什么不同?
- redis 采用的是 渐进式哈希,hashmap 采用的是一次性哈希
- 渐进式哈希
- 保存两个哈希表,一个新,一个旧。
- 每次进行增删改查时,都会检测是否正在进行 rehash,如果正在进行 rehash 操作,就会将 rehashindex 指向的桶中的所有元素移到新表中。
- 如果系统比较闲,则会出发定时函数来完成 rehash 操作
- 增操作直接在新表上进行
- 删改查操作先在旧表上操作,旧表上没有再去新表查找。
ConcurrentHashMap(jdk8)的多线程协同 rehash 是怎么回事?
- 多线程协助扩容,每个线程默认处理16个桶
- 读操作线程不需要帮忙扩容,写操作线程必须先帮忙扩容之后再进行写操作。
- 对于每个桶内的元素进行移动时,将其 hahscode 与 新
length
(这里不是 length-1 !) 做与操作,结果为0 放在低位,结果为1 放在高位 - 之所以这样做,是因为一个元素在扩容后的数组中的位置要么是在原位置,要么是原位置的基础上加上旧表的length得到新位置。
- 与旧表的 length = 4(100) ,只是单纯的看最高位是否为 1, 不为 1 放低位,为1 放高位。
为什么HashMap 允许 key/value 为 null,但ConcurrentHashMap不允许?
- ConcurrentHashMap 遇到 key/value 为 null 会报空指针错误
java类名是否允许相同?比如和jdk中某个类相同?
- 可以,只要不在同一个 packet 中即可!
lambda 表达式
- lambda 表达式中只允许引用声明为常量的局部变量
java 接口特性
- 一个接口的实现类可以实现多个接口
- 接口的实现类
(如果不是抽象类的话!)
则必须实现接口中的全部抽象方法 - 接口中的方法被默认设置为
public abstract
; 接口中的变量被默认设置为final static
, 所以必须初始化; - 接口没有构造函数,无法实例化
java四种访问权限
- public:跨类、跨包访问
- default:属性前什么都不加,只能跨类,不能跨包
- protected:子类可访问
- private:只有自己可以访问
java数组存储
- java数组是按维存储的!
- 比如二维数组相当于多个一维数组
Integer valueOf 缓存
- -128到127之间直接在缓存中取!
java基本数据类型
java基本数据类型一共8种,如下所示
类型 | 默认值 | 大小 | 最小值 | 最大值 |
---|---|---|---|---|
boolean | false | 1bit | 0 | 1 |
byte | 0 | 8bit/1byte | -128 | 127 |
short | 0 | 16bit/2byte | -32768(三万) | 32767 |
char | ‘\u0000’(也就是0) | 16bit | ‘\u0000’/0 | ‘\uffff’(即为65,535) |
int | 0 | 32bit/4byte | -2,147,483,648(20亿) | 2,147,483,647 |
float | 0.0f | 32bit/4byte | 略 | 略 |
long | 0L | 64bit/8byte | -9,223,372,036,854,775,808(-2^63) | 9,223,372,036,854,775,807 |
double | 0.0d | 64bit/8byte | 略 | 略 |
基本类型和包装类的区别,为什么要有包装类
- 包装类是对象,基本类型是普通变量
- 包装类是引用传递,基本类型是值传递
- 声明方式不同,存储位置不同
- 初始值不同,int初始值是0,包装类初始值都是null
- 为了使基本类型拥有对象的性质,保证其面向对象的完整性。
Author 段新朋
LastMod 2020-07-20