1. HashSet是一个集合,也就是说是无序,且惟一的;
2. Contains进行比较时,如果是Object对象,会比较地址计算出的HashCode;如果是String则比较字符串内容的HashCode
3. HashSet有缓存,第一次Contains完成后,会缓存所有的HashCode,以备以后使用。所以说HashSet最好只用来存储不可变对象,否则contains方法的返回值是不准确的
切记:
1:对于不可变类(String、Integer、以及自己定义的不可变类等),要保证equals返回true的时候,它们的hashcode的值相等。
2:对于不可变类,也要尽量满足1。以避免出现上面说的Set比较时出现的问题。
3:覆盖一个类的equals方法的时候,要注意可交换性,要保证a.equals(b)的值一定等于b.equals(a)的数值。
当GetHashCode可以直接分辨出不相等时,Equals就没必要调用了,而当GetHashCode返回相同结果时,Equals方法会被调用从而确保判断对象是否真的相等。
所以,还是那句话:GetHashCode没必要一定把对象分辨得很清楚(况且它也不可能,一个int不可能代表所有的可能出现的值),有Equals在后面做保障。GetHashCode仅需要对对象进行快速判断。
String 的 hashCode 是按字符的hashCode 排列的,然后字符相同,hashCode就想同,而且hashCode 没有set方法,也不能改变。。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HashSetEqual
{
class Program
{
static void Main(string[] args)
{
var o1 = new a(1); //GetHashCode返回1
var o2 = new a(2); //GetHashCode返回0
var o3 = new a(3); //GetHashCode返回1
var dic = new Dictionary<a, object>();
dic.Add(o1, 123);
Console.WriteLine("分隔符");
Console.WriteLine(dic.ContainsKey(o2));
Console.WriteLine("分隔符");
Console.WriteLine(dic.ContainsKey(o3));
}
}
class a
{
public int Id { get; private set; }
public a(int i)
{
Id = i;
}
public override bool Equals(object obj)
{
Console.WriteLine("Equals");
if (obj == null || GetType() != obj.GetType())
{
return false;
}
return Id == ((a)obj).Id;
}
//返回余2的结果
public override int GetHashCode()
{
Console.WriteLine("GetHashCode");
return Id % 2;
}
}
}
JAVA:
hashcode是通过将内部存储地址映射成一个整型值,这个整型值就是hashcode。java语言规范对hashcode的实现不做要求,这是JVM的实现。需要注意的是:
对于有些架构(例如64位),内存地址空间超过int的表示范围,所以不同对象地址的映射值必然会有相同的,所以hashcode不能确定两个是否相等
C#:
Object.GetHashCode方法的实现同样是基于对象引用(其实就是对象的内部存储地址)来计算。而且MSDN文档同样明确表明:
.NET Framework 不充当防护措施 GetHashCode 方案的默认值实现,因此,此方法返回的值可能不同于 .NET Framework 版本和平台之间,如 32 位和 64 位平台。
1. 如果两个对象equal,则hashcode必须一致;
2. 如果两个对象的hashcode一致,但两个对象不一定equal;