我有一个班级学生和马克斯。
我使用Student
Object
作为HashMap
的关键字并将其标记为值。
如果我不覆盖hashMap
并且等于,它仍然可以正常工作。
我。如果没有覆盖equals()
和hashcode()
,有人可以解释它在内部是如何工作的吗?
II。如果我仅覆盖hashcode()
iii.what如果我仅覆盖equals()
class Student {
String name;
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
String lastName;
Student(String name, String lastName){
this.name = name;
this.lastName = lastName;
}
public String toString(){
return(" Name : " + this.getName() + " Last Name : " + this.getLastName());
}
}
class Marks {
Student s;
String marks;
public Student getS() {
return s;
}
public void setS(Student s) {
this.s = s;
}
public String getMarks() {
return marks;
}
public void setMarks(String marks) {
this.marks = marks;
}
Marks (Student s, String marks){
this.marks = marks;
this.s = s;
}
public String toString(){
return(" Marks : " + this.getMarks());
}
}
public class Main {
public static void main(String[] args) {
Student s1 = new Student("Vishnu","Verma");
Student s2 = new Student("Amit","Sharma");
Marks m1 = new Marks(s1,"65%");
Marks m2 = new Marks(s2,"67%");
Map <Student,Marks>map = new HashMap<Student,Marks>();
map.put(s1, m1);
map.put(s2, m2);
System.out.println(map);
}
}
答案 0 :(得分:2)
如果它们的引用相等,它将认为对象是相等的。即他们指向同一个物体。
答案 1 :(得分:1)
让我们来看看HashMap
是如何运作的(在简单的情况下)。
首先我们创建哈希表:
当我们添加密钥时 - &gt;值映射到我们的HashMap
我们:
hashCode
hashCode
和上面的哈希表,我们选择一个桶要从我们的HashMap
我们获取密钥值
hashCode
hashCode
和上面的哈希表,我们选择一个桶equals
到所请求密钥的键,如果是,则返回值equals
请求的键并返回其值null
。所以,回答你的问题:
如果不覆盖equals()
和hashcode()
,它内部如何处理?
我认为你的意思是你不覆盖任何东西并将其保留为默认行为。
在这种情况下,HashMap
使用Object.hashCode
和Object.equals
; HashMap
的行为与IdentityHashMap
完全相同 - 即它会使用System.identityHashCode
来计算hashCode
,并使用==
来测试相等性。
此默认行为仅在处理class
的同一实例时才能正常工作。
如果我仅覆盖hashcode()
?
TL; DR:您的HashMap
的行为与上述相同。
您hashCode
将用于在插入(2)和检索(2)期间选择存储桶,但默认equals
将用于确定是否找到了正确的密钥。
Map
可能与上述情况类似,因为hashCode
实施不太可能违反hashCode
的一般合同,即只有完全相同的实例才会等于它自己,如果hashCode
编译的事实是它必须在同一个实例上多次调用时返回相同的值,它必须通过扩展符合这个要求。
NB:相反的情况并非如此。由于equals
返回不同哈希码的项目,仅覆盖hashCode
会立即违反equals
的合同。这会将基于散列的集合从HashMap
分解为HashSet
,因为您将拥有重复的密钥,并且集合将显示未定义的行为。
这个问题是,除了你认为hashCode
的对象之外,还有更多的对象会返回相同的equals
- 虽然这是哈希本质的一部分,但你会复合这个问题。
在这种情况下,您的HashMap
可能效率低下。
为了说明我的意思,请考虑一个带有一个元素的class
的简单示例:
class IntHolder {
int value;
//getter setter
}
如果我们使用默认equals
和hashCode
,则我们的Map
会出现以下行为:
final Map<IntHolder, String> map = new HashMap<>();
final IntHolder a = new IntHolder();
a.setValue(7);
final IntHolder b = a;
final IntHolder c = new IntHolder();
c.setValue(7);
map.put(a, "A");
System.out.println(map.get(a)); // --> A
System.out.println(map.get(b)); // --> A
System.out.println(map.get(c)); // --> null
map.put(c, "C");
System.out.println(map.get(a)); // --> A
System.out.println(map.get(b)); // --> A
System.out.println(map.get(c)); // --> C
即。 Map
只会考虑==
的两个键(例如a
和b
)。
如果您“丢失”对密钥实例的引用,您将永远无法将其恢复。所以,如果你这样做了:
c = null;
如果没有循环Map
,你就永远不会再次从Map
中获得“C”。
OP问:我们如何确定只需要覆盖hashCode()或者只需要覆盖equals()?
您应该只覆盖这些方法的 或 。
从来没有用于仅覆盖equals
或仅覆盖hashCode
的用例。
答案 2 :(得分:0)
如果您的班级没有实施,那么hashCode
和equals
会回退到以下Object
实施:
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
因此hashCode
的实现因运行时环境的不同而有所不同,但关于HashMap
更有趣,equals
方法要求两个对象是相同的实例才是相同的!
Object
无法猜测是什么让两个实例相等,所以它默认为最强约束。
答案 3 :(得分:0)
如果不覆盖equals和hashcode,则实现继承自Object。
HashMap使用方法hashcode()来确定条目将在哪个子列表中。因此,如果您不覆盖(或者更糟糕的是,覆盖并为每个实例返回相同的值)方法,HashMap可能会将每个条目存储在同一个子列表中。这会使地图变慢,但输入值仍然有用。
有关上一个问题,请参阅https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--
长话短说:你不应该仅仅覆盖一个。你应该覆盖它们。