Java 容器知识点(简)
来源:互联网 发布:怎么克服懒惰 知乎 编辑:程序博客网 时间:2024/06/08 05:20
1、加入Set的元素必须定义equals()方法以确保对象的唯一性。关于Set子类集合的元素顺序问题:HashSet以某种神秘的顺序保存所有的元素(O(∩_∩)O~)、LinkedHashSet按照元素的插入顺序保存元素、TreeSet按照排序顺序维护元素。
2、除了并发应用,Queue在JavaSE5中仅有的两个实现是LinkedList和PriorityQueue。
3、散列与散列码
Object的hashcode方法默认使用对象的地址计算散列码,Object的equals方法默认比较的也是对象的地址。因此如果使用自己的类作为Hash***的键,必须同时重载hashcode和equals方法。其中,equals用于判断当前的键是否与表中的键相等,而hashcode用于快速查找。
if(map.containsKey(key)){
map.get(key);
}
-->查看containsKey的源码:
@Override public boolean containsKey(Object key) { if (key == null) { return entryForNullKey != null; } int hash = Collections.secondaryHash(key); HashMapEntry<K, V>[] tab = table; for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)]; e != null; e = e.next) { K eKey = e.key; if (eKey == key || (e.hash == hash && key.equals(eKey))) { return true; } } return false;}
我们发现Map确实是使用equals来判断当前的键是否与表中的键相等。
使用散列给我们带来了什么好处呢?那就是速度。
我们知道线性查询是最慢的查询方式,散列的价值在于速度:散列使得查询得以快速的进行。散列将键保存在某处,以便能够很快的找到。而存储一组元素最快的数据结构是数组,所以使用它来表示键的信息(是键的信息,而非键本身),数组并不保存键本身,而是通过键对象生成一个数字,将其作为数组的下标,这个数字就是散列码。
为了解决数组容量被固定的问题,不同的键可以产生相同的下标,也就是是可能存在冲突的,因此数组的多大就不重要了,任何键都可以在数组中找到它的位置。
于是查询一个值的过程首先就是计算散列码,然后使用散列码来查询数组。如果要是没有冲突,那就有了一个完美的散列函数了。但这种情况只是特例。(完美的散列函数只在EnumMap和EnumSet中得以实现,因为enum定义了固定数量的实例)。解决冲突的方式如下:
数组仅保存键的信息,而值都保存在List中。然后再对List中的元素进行线性查询。这部分查询相对会慢一些。但是如果散列函数好的话,数组每个位置就只有较少的值。因此不是查询整个List,而是快速的跳到数组的某个位置,只对很少的元素进行比较。这就是HashMap如此快的原因。借用一张别人画的图,说明HashMap的内部结构:
理解如下代码,可以更好的明白HashMap的工作原理:
为了使散列均匀,bucket(桶位)的数量通常是质数。注意:为了能够自动的处理冲突,使用了一个LinkedList,每个新元素只是直接添加到list末尾的某个特定的桶位中。
3.1、如何覆写hashcode()
要想使hashcode()实用,它必须速度快,有意义。也就是说它必须基于对象的内容生成散列码。以下是Joshua Bloch为编写一份像样的hashcode给出的指导:
1)给int变量result赋予某个非零的常量值,比如result = 17;
2)给对象内每个有意义的域f(即每个可以做equals操作的域)计算一个int散列码
域类型 计算
boolean c=(f?0:1)
byte、short、int或char c= (int)f
long c= (int)(f^(f>>32))
float c= Float.floatToIntBits(f)
double long l = Double.doubleToLongBits(f)
c= (int)(l^(l>>32))
object,其equals()调用这个域的equals c = f.hashCode()
数组 对每个元素应用上述规则
3)合并计算得到的散列码
result = 37*result + c;
4)返回result
5)检查hashCode()最后生成的结果,确保相同的对象有相同的散列码。
示例:一个类具有如下的两个字段:
private String s;
private int id;
public int hashCode(){
int result = 37;
result = 37*result + s.hashCode();
result = 37*result + id;
return result;
}
public boolean equals(Object o){
return o instanceof ClassA && s.equals(((ClassA)o).s) && id == ((ClassA)o).id
}
4、HashMap 性能调整
与HashMap相关的术语:
容量:表中的桶位数
初始容量:表在创建的时候所拥有的桶位数
尺寸:表中当前存储的项数
负载因子:尺寸/容量。空表的负载因子是0,而半满表的负载因子是0.5,以此类推。负载轻的表,则产生的冲突的可能性较小,因此对于插入和查找都是理想的。HashMap和HashSet都具有允许你指定负载因子的构造器,表示当负载情况达到该负载因子的水平时,容器将自动的增加(桶位数),实现的方式是容量大致加倍,并重新将现有对象分配到新的桶位集中(这被称为再散列)。
HashMap默认的负载因子是0.75.
- Java 容器知识点(简)
- 牛客网刷题知识点总结(五)java容器
- JAVA集合(容器)类知识点汇总
- java知识点汇总之四容器
- Tinking in java 琐碎知识点之集合(容器)
- java基础技术知识点总结——容器、迭代器
- 容器知识点总结
- 容器 知识点总结
- 容器vector相关知识点
- spring IOC 容器知识点
- Java知识点(更新)
- java 知识点(重要)
- java 知识点(重要)
- java 知识点(重要)
- java 知识点(中)
- java知识点(下)
- java知识点(后台)
- java 知识点(重要)
- 2017it技术人员都该参加这些会议
- KMP的简单实现
- **ANDROID**# 第七章图形与图像处理(静态处理) > Bitmap是有像素点构成的点阵图。 ------ ## 使用简单的图片 ---- * 通过Drawable对象进行访问。
- Flume和Logstash的那些事儿
- 成为Java顶尖程序员 ,看这11本书就够了
- Java 容器知识点(简)
- 深入探究connect函数
- jsp隐式对象
- TCP/IP协议,HTTP协议--面试必备
- 下载CentOS的Linux内核的源代码
- Java中如何遍历Map对象的4种方法
- 1X1卷积核到底有什么作用
- 掌握jQuery插件开发,这篇文章就够了
- 数论总结之Lucas