今天下午,我遇到了一个面试问题,如下所示:
// 创建一个字符串到字符串的哈希映射
HashMap<String,String> map1 = new HashMap<>();
// 将键为 "a" 的值设为 "a"
map1.put(new String("a"),"a");
// 再次将键为 "a" 的值设为 "b",这将覆盖之前的值 "a"
map1.put(new String("a"),"b");
// 输出映射的大小,即键值对的数量
System.out.println(map1.size());
面试官: 上面代码的输出会是什么?
我: 1
面试官: 为什么?如果我们使用“new String(a)”,将会创建一个新的String对象,那和原来的不一样,为什么结果会是1?
我: 不太明白为什么但结果会是1。
咱们稍微改改问题,好不?
假设我们有如下的 Emp 类定义:
Emp 类定义如下:
public class Emp {
private String 名称;
@Override
public String toString() {
return "Emp{" +
"名称='" + 名称 + '\'' +
'}';
}
public Emp(String name) {
this.名称 = name;
}
public String getName() {
return 名称;
}
public void setName(String name) {
this.名称 = name;
}
}
- 在这里我们定义了一个名为
Emp
的公共类。 - 类中有一个私有变量
名称
,其类型是String
。 toString()
方法被重写以返回包含员工名称的字符串。- 构造函数
Emp(String name)
接收一个String
类型的参数,并将其赋值给名称
变量。 getName()
方法返回名称
变量的值。setName(String name)
方法允许设置名称
变量的值。
面试官:下面这段代码输出什么?
// 创建一个HashMap, 使用Emp作为键,String作为值
HashMap<Emp, String> map2 = new HashMap<>();
map2.put(new Emp("a"), "a");
map2.put(new Emp("a"), "b");
// 这是输出map2的大小
System.out.println(map2.size());
我:二
面试官:为什么第一种情况下我们得到1,而在第二种情况中我们得到2?
我:我想不出具体原因,但这通常是这样的情况。
面试官:好的,这样就可以了。
面试结束后,我才意识到答案!
String
类重写了 equals
方法。str1.equals(str2)
会比较字符串值并返回 true
或 false
。现在在 HashMap
中,比较键时发现“a”等于“a”(尽管这两个 String
对象在内存地址上是不同的),因此它们的 hashCode
也相同。因此,put()
方法会发现“a”已经在映射中,并且它会用“b”覆盖“a”的值,而不是创建一个新的条目。因此,映射的大小将是 1。
但在 Emp
类的情况下,没有重写 equals
方法,而 Object
类的 equals
方法是根据引用是否指向同一内存地址来返回 true
或 false
(基于 ==
操作符而不是值的逻辑相等)。因此,在 Emp
类中,调用 Object
类的 equals
方法时,如果 map
中已有键 new Emp(a)
,而在下一个 put()
中尝试插入另一个键 new Emp(a)
,则 equals
方法会返回 false
。由于 equals
方法返回 false
,map.put()
将创建一个新的键 new Emp("a")
,从而使 map
的大小将变为 2。
我希望这能为我们增加一些知识的价值。请关注我并通过评论和分享我的文章来支持我,与其他开发者分享。
注:保留“fellow developers”为英文原样。
谢谢你看完这篇文章。继续嗨皮哦
共同学习,写下你的评论
评论加载中...
作者其他优质文章