集合 的体系:
------------| Collection 单例集合的根接口
----------------| List 如果是实现了List接口的集合类,具备的特点: 有序,可重复。
-------------------| ArrayList ArrayList 底层是维护了一个Object数组实现的。 特点: 查询速度快,增删慢。
-------------------| LinkedList LinkedList 底层是使用了链表数据结构实现的, 特点: 查询速度慢,增删快。
-------------------| Vector(了解即可) 底层也是维护了一个Object的数组实现的,实现与ArrayList是一样的,但是Vector是线程安全的,操作效率低。
----------------| Set 如果是实现了Set接口的集合类,具备的特点: 无序,不可重复。
-------------------| HashSet 底层是使用了哈希表来支持的,特点: 存取速度快.
hashSet的实现原理:
往Haset添加元素的时候,HashSet会先调用元素的hashCode方法得到元素的哈希值 ,
然后通过元素 的哈希值经过移位等运算,就可以算出该元素在哈希表中 的存储位置。
情况1: 如果算出元素存储的位置目前没有任何元素存储,那么该元素可以直接存储到该位置上。
情况2: 如果算出该元素的存储位置目前已经存在有其他的元素了,那么会调用该元素的equals方法与该位置的元素再比较一次,如果equals返回的是true,那么该元素与这个位置上的元素就视为重复元素,不允许添加,如果equals方法返回的是false,那么该元素运行 添加。
问题1:Java中Set的contains()方法 —— hashCode与equals方法的约定及重写原则
Set的contains(Object o) 方法详解
Java的API文档指出: 当且仅当 本set包含一个元素 e,并且满足(o==null ? e==null : o.equals(e))条件时,contains()方法才返回true. 因此 contains()方法 必定使用equals方法来检查是否相等.
equals()与hashCode()方法之间的设计实现原则为:
如果两个对象相等(使用equals()方法),那么必须拥有相同的哈希码(使用hashCode()方法).
即使两个对象有相同的哈希值(hash code),他们不一定相等.意思就是: 多个不同的对象,可以返回同一个hash值.
hashCode()的默认实现是为不同的对象返回不同的整数.有一个设计原则是,hashCode对于同一个对象,不管内部怎么改变,应该都返回相同的整数值.
问题2:JAVA HashSet 去除重复值原理]
Java中的set是一个不包含重复元素的集合,确切地说,是不包含e1.equals(e2)的元素对。Set中允许添加null。Set不能保证集合里元素的顺序。
在往set中添加元素时,如果指定元素不存在,则添加成功。也就是说,如果set中不存在(e==null ? e1==null : e.queals(e1))的元素e1,则e1能添加到set中。
Hashcode约定
1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。
2. 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。
3. 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。
package com.darren.test.overide;
public class CustomString {
private String value;
public CustomString() {
this("");
}
public CustomString(String value) {
this.value = value;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj instanceof CustomString) {
CustomString customString = (CustomString) obj;
return customString.value.equals(value);
} else {
return false;
}
}
@Override
public int hashCode() {
// return super.hashCode();
return 1;
}
}
package com.darren.test.overide;
import java.util.HashSet;
import java.util.Set;
public class HashSetTest {
public static void main(String[] args) {
String a = new String("A");
String b = new String("A");
CustomString c = new CustomString("B");
CustomString d = new CustomString("B");
System.out.println("a.equals(b) == " + a.equals(b));
System.out.println("c.equals(d) == " + c.equals(d));
Set<Object> set = new HashSet<Object>();
set.add(a);
set.add(b);
set.add(c);
set.add(d);
System.out.println("set.size() == " + set.size());
for (Object object : set) {
System.out.println(object);
}
}
}
//输出结果
a.equals(b) == true
c.equals(d) == true
set.size() == 2
com.darren.test.overide.CustomString@1
A
在HashSet中,基本的操作都是有HashMap底层实现的,因为HashSet底层是用HashMap存储数据的。当向HashSet中添加元素的时候,首先计算元素的hashcode值,然后用这个(元素的hashcode)%(HashMap集合的大小)+1计算出这个元素的存储位置,如果这个位置位空,就将元素添加进去;如果不为空,则用equals方法比较元素是否相等,相等就不添加,否则找一个空位添加。https://blog.csdn.net/zpf336/article/details/42397415
总结一下:hashmap 判断是否包含此key需要重写hashcode和equals /ArrayList 只需要重写equals即可
如何重写 看这里