今天下午,我遇到了一个面试问题,如下所示:
// 创建一个字符串到字符串的哈希映射
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”为英文原样。
谢谢你看完这篇文章。继续嗨皮哦
共同學習,寫下你的評論
評論加載中...
作者其他優質文章