Java SE
集合
HashMap
HashMap 中如何确定key在tab中的位置
1、 通过hash()
计算方式为: (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)
计算hash 值
2、 n=table.length
3、 计算位置 i = (n - 1) & hash
tips: 一些常见类的hashCode 计算方式
- Integer、Byte、Char :其本身
- String :s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1] ,String的hash值只会计算一次,之后就换缓存在String类的hash属性中
- Long: (int)(value ^ (value >>> 32)
HashMap的put流程
Scala
泛型
Scala中获取类型信息的几种用法
方式 | 作用 | 注 | |
---|---|---|---|
getClass | 得到的是Class[A]的某个子类 | val ab:Class[A] = a.getClass这种写法是错误的,因为Class[A]不支持协变 | |
classOf[A] | 得到是正确的Class[A] | Java里的 Class[T]是不支持协变的,所以无法把一个Class[_ < : A] 赋值给一个 Class[A] | |
typeOf | 使用typeOf可以得到更为具体的泛型信息,这也意味着,可能使用classOf得到判断为正确的泛型,使用typeOf是错误的 | 例如:classOf[List[Int]] == classOf[List[String]]为true ;typeOf[List[Int]] == typeOf[List[String]]为False;typeOf还会关注类型中的泛型信息,更加细致。 |
由于java虚拟机在运行时,会擦除泛型信息(所有泛型类均被当作Object),Scala提供额外的方式来获得运行时泛型信息。
def foo[T:Manifest] (x: List[T]) //类型信息作为参数,在上下文中传递
写法 | 作用 |
---|---|
Manifest | 获取详细的泛型信息,2.10以上版本使用TypeTag代替 |
ClassManifest | 获取较弱的泛型信息,2.10以上版本使用ClassTag代替 |
协变、逆变与不可变
类型 | 写法 | 说明 | 正确举例 | 错误举例 |
---|---|---|---|---|
协变 | C[+T] | 如果A是B的子类,则C[A]是C[B]的子类 | val a:C[Super] = new C[Sub] | val a:C[Sub] = new C[Superb] |
逆变 | C[-T] | 如果A是B的子类,则C[B]是C[A]的子类 | val a:C[Sub] = new C[Superb] | val a:C[Super] = new C[Sub] |
不可变 | C[T] | 如果A是B的子类,则C[A]和C[B]没有从属关系 | 以上两种写法均不正确 |
注:举例中Super是Sub的父类。
泛型界定
名称 | 写法 | 说明 | 举例 | 举例备注 |
---|---|---|---|---|
类型变量界定(Type Variable Bound) | [T<C[T]] | 对泛型T添加约束,添加上届约束,使得泛型T拥有类型C的方法 | [T<:Comparable[T]] | 只需继承Comparable接口即可 |
视图界定(View Bound) | [T<%C[T]] | (语法糖)与类型界定相比,视图界定还允许,不遵循C[T]约束的类型C,通过隐士转换转为遵循C[T] | [T<%Comparable[T]] | 例如Int并未继承Comparable接口,但是可以通过隐式转换转为RichInt从而满足范式要求。因此传入Int类型合法 |
上届(Upper Bound)、下届(Lower Bound) | [T>:C] [T<:C] | 与java中上下届含义一致 | ||
上下文界定(Context Bound) | [T:C] | (语法糖)与视图界定相似,不同的是这种方式传入的是一个隐式值。 | [T: Comparator] | 这里传入的隐士值既可以再参数列表中写出也可以不写,通过implicitly[Comparator[T]]仍然可以获得这个入参 |
注: 视图界定与上下文界定均属于语法糖,分别可以传入隐式函数、隐式值,来操作范式的实际值以获得增强效果。