HashMap源代码的阅读
Created by 徐庆杰, last modified on 八月 08, 2023
从名字上来看,HashMap应该是通过HashCode的方法存储Key值已达到降低检索时间复杂度的目的的
HashMap继承了AbstractMap<K,V>抽象类,并且继承了Map<K,V>接口
而AbstractMap<K,V>实现了Map<K,V>中的部分方法
default关键字
在翻找Map<K,V>接口的定义时发现,其有一部分的方法定义前面有 default 关键字,而带了 default 关键字的方法都有方法体。
经查证使用 default 或者 static 关键字修饰的方法必须有方法体,且 default 和 static 关键字只能出现其中一个。
Java泛型
为了兼容各种类型的数据在Map中的存储,Java使用了泛型定义了Map接口
泛型类中,静态方法和静态变量不能使用参数类型
在静态方法中可以使用自身的方法签名中新定义的类型参数,而不能使用泛型中定义的类型参数
public class Test2
{ // 泛型类定义的类型参数 T 不能在静态方法中使用 public static E show(E one){ // 这是正确的,因为 E 是在静态方法签名中新定义的类型参数 return null; } }
泛型类
泛型类中可以接受多个类型参数
public class MultiType <E,T> {
E value1;
T value2;
public E getValue1(){
return value1;
}
public T getValue2(){
return value2;
}
}
泛型方法
public class TestMethod { public <T, S> T testMethod(T t, S s) { return null; } }
泛型方法中可以使用泛型类的方法参数
在调用泛型方法的时候,可以显式地指定类型参数,也可以不指定。 当泛型方法的形参列表中有多个类型参数时,在不指定类型参数的情况下,方法中声明的的类型参数为泛型方法中的几种类型参数的共同父类的最小级,直到 Object。
在指定了类型参数的时候,传入泛型方法中的实参的数据类型必须为指定数据类型或者其子类。
类型擦除
泛型信息只会存在于代码编译阶段,在代码编译结束后,与泛型相关的信息会被擦除调,专业属于叫类型擦除。也就是说,成功编译过后的class文件中不包含泛型信息,泛型信息不回进入到运行时阶段
public class Caculate
编译结束后得到的代码是
public class Caculate { public Caculate()
数据的内容在计算结束之后就会被擦除,只会留下一个Object类型的属性
再看一个例子,假设定义一个泛型类如下:
public class Caculate
{
private T num;
}
将其反编译: public class Caculate {
public Caculate() {}// 默认构造器,不用管 private Number num;
}
使用
在类型擦除之后 泛型的类型不是Object 而是Number
(1)对于<? extends 类型>,编译器将只允许读操作,不允许写操作。即只可以取值,不可以设值。
(2)对于<? super 类型>,编译器将只允许写操作,不允许读操作。即只可以设值(比如 set 操作),不可以取值(比如 get 操作)。
我们何时使用 extends,何时使用 super 通配符呢?为了便于记忆,我们可以用 PECS 原则:Producer Extends Consumer Super。
即:如果需要返回 T,则它是生产者(Producer),要使用 extends 通配符;如果需要写入 T,则它是消费者(Consumer),要使用 super 通配符。
CSDN链接: https://blog.csdn.net/weixin_45395059/article/details/126006369
Map<K,V>
在Map中包含一些只定义,未实现的方法
另外 Map中主要定义了Entry接口并实现了部分方法
通过Map中实现的entrySet方法可以发现,在Map的接口中想让后续实现的所有map都是用Entry作为存储的基本单元
Entry<K,V>
AbstractMap<K,V>
这是一个抽象类
包含一些不涉及查询和存储的预定义方法,涉及到存储的部分没有实现
containKey
containValue
从这两个方法来看,在AbstractMap中是支持null值作为key或者value的
remove方法中,如果存在key值,返回key对应的value值,否则返回null
putAll中只能放入K,V或者其子类
KeySet方法能获取存储key的set结构
set结构是匿名内部类继承了AbstractSet,这个set能够直接通过迭代器获得Key列表的所有值
values能获得所有value的Collection
equals方法在AbstractMap中实现了,其中进行了
1.是否为同一个对象的判断
2.是否为同一个类型的判断
3.长度是否相同的判断
4.是否包含相同key的判断
5.key相同时,value是否相同的判断
hashCode是entry对象hashCode的和
AbstractMap.SimpleEntry和AbstractMap.SimpleImmutableEntry中实现了Map.Entry未实现的一些方法
SimpleImmutableEntry中不能进行setValue的操作