Java哈希代码,人工字段?

Java哈希代码,人工字段?,java,field,hashcode,Java,Field,Hashcode,想象一下以下问题: // Class PhoneNumber implements hashCode() and equals() PhoneNumber obj = new PhoneNumber("mgm", "089/358680"); System.out.println("Hashcode: " + obj.hashCode()); //prints "1476725853" // Add PhoneNumber object to HashSet Set<P

想象一下以下问题:

    // Class PhoneNumber implements hashCode() and equals()
PhoneNumber obj = new PhoneNumber("mgm", "089/358680");
System.out.println("Hashcode: " +
    obj.hashCode());  //prints "1476725853"

// Add PhoneNumber object to HashSet
Set<PhoneNumber> set = new HashSet();
set.add(obj);

// Modify object after it has been inserted
obj.setNumber("089/358680-0");

// Modification causes a different hash value
System.out.println("New hashcode: " +
    obj.hashCode()); //prints "7130851"

// ... Later or in another class, code such as the following
// is operating on the Set:

// Unexpected Result!
// Output: obj is set member: FALSE
System.out.println("obj is set member: " +
    set.contains(obj));
//类PhoneNumber实现hashCode()和equals()
PhoneNumber obj=新电话号码(“米高梅”,“089/358680”);
System.out.println(“哈希代码:”+
obj.hashCode())//打印“1476725853”
//将PhoneNumber对象添加到HashSet
Set=newhashset();
集合。添加(obj);
//插入对象后修改对象
对象设置编号(“089/358680-0”);
//修改会导致不同的哈希值
System.out.println(“新哈希代码:”+
obj.hashCode())//打印“7130851”
// ... 稍后或在另一个类中,使用如下代码
//正在机组上运行:
//意外的结果!
//输出:obj已设置成员:FALSE
System.out.println(“obj被设置为成员:”+
集合包含(obj));

如果我有一个类,并且我希望我的所有字段都是可编辑的,并且仍然能够使用set/hashCode。在创建对象时设置的类中创建一个人工的不可编辑字段是一个好主意吗?例如,以毫秒为单位的当前时间。当我得到该字段时,我可以将哈希代码建立在它的基础上,并且我仍然能够编辑所有“真实”字段。这是个好主意吗

为数据对象设置一个唯一标识符通常是有意义的,尤其是当您要将它们持久化到某个数据库中时。它将允许您轻松实现
equals
hashCode
,这将仅依赖于此单个标识符


我不确定以毫秒为单位的当前时间是否是最佳选择,但您肯定应该生成一些唯一的ID。

将可变对象存储在哈希集中,或者将它们用作哈希映射中的键,这绝对不是一个好主意,正是因为您在代码中说明了这一点

另一方面,定义一个用作对象的
ID
的人工数字,会破坏首先使用哈希代码的目的,因为它无法通过将搜索限制在具有相同哈希代码的对象来帮助您找到与给定对象相等的对象


事实上,您的解决方案与构建从“人工哈希代码”到可变的
PhoneNumber
对象的
Map
没有什么不同。如果您需要通过关联查找对象,
HashMap
从一个人工ID到可变对象是一个不错的选择。

我坚信您展示的是一个糟糕的用例:如果您需要修改
集中的对象,您一定要删除旧的对象并重新添加新的对象(或使用另一个
java.util.Collection
)。以您的示例为例:

Set<PhoneNumber> set = new HashSet();
set.add(obj);

// Modify object after it has been inserted
set.remove(obj);
obj.setNumber("089/358680-0");
set.add(obj);
Set Set=newhashset();
集合。添加(obj);
//插入对象后修改对象
设置。移除(obj);
对象设置编号(“089/358680-0”);
集合。添加(obj);
hashCode
的全部目的是创建一个类似对象的bucket,以减少搜索空间,因此它应该是不变的,但对您很有用(如果使用人工字段,以后如何在集合中找到对象?如果没有任何类型的持久性存储,如何检索此人工字段-数据库中的id是使用人工字段IMHO的例外)

解释

hashCode
的全部目的就是创建一个类似的bucket 对象以减少搜索空间


请看以下示例代码:.I(错误地)使用相同的哈希代码创建对象,然后将两者添加到一个集合中;正如预期的那样,集合中同时包含这两个元素,因为哈希代码用于检索发生冲突的元素,然后调用
equals
方法来解决此冲突。冲突(读取返回相同散列码的不同对象是不可避免的,正确设计的散列码函数的目标是尽可能减少它们。

只有在这种行为有意义的情况下。您如何根据“人工”字段在集合中查找某些内容?当然,这称为“数据封装”:以毫秒为单位的时间不多,但可能是GUID。@Specializet的可能副本:这完全是胡说八道。HashSet是事实上的标准选择,因为它的性能特点。使用hashCode不会将您限制为2^32个元素。例如,切换到TreeSet并不能解决OP的问题。虽然我同意使用唯一的IdentifIf对于数据库,我倾向于不同意这是否是OP所做工作的好方法。他使用
Set
这一事实让我觉得他期望重复的对象,只想保留唯一的对象。基于hashCode(因此等于)on unique identifiers将确保没有两个对象是相同的,即使它们具有相同的实际内容。这取决于生成唯一标识符的时间。如果它仅在创建新对象时生成(而不是从DB或其他持久存储加载现有对象)另一方面,如果它是为类的任何新实例生成的,那么它将毫无意义,因为在这种情况下,您可以简单地使用对象的equals(=)的默认实现还有hashCode。是的,这正是我同意你在数据库部分的原因。关于发布的问题,根本没有提到数据库。至于你评论的第二部分,OP仍然需要覆盖equals()&hashCode()并且不能使用对象的默认实现。@实际上,如果每个被实例化的对象都得到一个新生成的标识符(在这种情况下,我想我们都同意这个标识符是无用的),a等于(b)当且仅当a==b时,将返回true。这就是为什么我说equals的默认实现与比较两个对象的生成标识符的行为相同。