Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/383.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 字符串与字符串缓冲区作为HashMap键_Java_String_Hashmap_Stringbuilder_Stringbuffer - Fatal编程技术网

Java 字符串与字符串缓冲区作为HashMap键

Java 字符串与字符串缓冲区作为HashMap键,java,string,hashmap,stringbuilder,stringbuffer,Java,String,Hashmap,Stringbuilder,Stringbuffer,我试图理解为什么字符串和Stringbuilder/StringBuffer在用作Hashmap键时被区别对待。让我用以下插图来澄清我的困惑: 示例#1,使用字符串: String s1 = new String("abc"); String s2 = new String("abc"); HashMap hm = new HashMap(); hm.put(s1, 1); hm.put(s2, 2); System.out.println(hm.size()); 上面的代码片段打印“1” 示

我试图理解为什么字符串和Stringbuilder/StringBuffer在用作Hashmap键时被区别对待。让我用以下插图来澄清我的困惑:

示例#1,使用字符串:

String s1 = new String("abc");
String s2 = new String("abc");
HashMap hm = new HashMap();
hm.put(s1, 1);
hm.put(s2, 2);
System.out.println(hm.size());
上面的代码片段打印“1”

示例2,使用StringBuilder(或StringBuffer):

上面的代码片段打印“2”


任何人都可以解释行为上的差异。

StringBuilder使用
对象的默认
hashcode()
实现,而字符串是通过映射键的值进行比较的

Map
的工作方式(特别是HashMap)是利用对象的
hashcode
,而不是类的内容

注意:地图上缺少参数化:

HashMap yourMap = new HashMap();
//Should be
Map<String, Integer> yourMap = new HashMap<>();

StringBuilder/Buffer不重写hashCode和equals。这意味着对象的每个实例都应该是唯一的哈希代码,其值或状态无关紧要。您应该使用字符串作为键

StringBuilder/Buffer也是可变的,将其用作HashMap的键通常不是一个好主意,因为将值存储在它下面会导致修改后无法访问该值


我注意到您正在使用新字符串(“abc”);这意味着您知道字符串a=“abc”和字符串b=“abc”是相同的

因此,a==b返回true。a.equals(b)返回true

但是,同样的事情对StringBuffers不起作用,因为它的equals不考虑对象的值,只考虑其哈希代码

如果查看StringBuffer,您将看到它使用Object.equals,这是

public boolean equals(Object obj) {
    return (this == obj);
}
而字符串的等号为:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String) anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                        return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

要理解这种行为,理解Hashmaps是如何工作的是很重要的。哈希映射使用键对象(本例中为字符串对象)返回的哈希代码值将它们存储到称为bucket的适当内存分区中。因此,在检索与之相关联的值时,hashmaps需要找到存储密钥的分区,然后针对该密钥返回值。Hashmaps根据密钥的哈希代码值标识隔室

现在,想象一下,如果我有两个具有相同哈希代码值的对象,会发生什么?在这种情况下,hashmap首先需要知道两个对象是否相同,因为如果它们相同,则表示映射中只有一个条目,与该键关联的现有值将被替换为新值。但是,仅仅拥有相同的散列码并不意味着两个键是相等的。因此,相等性是通过对键对象调用.equals()方法来确定的。如果.equals()返回true,则对象是相等的,在这种情况下,哈希映射需要更新现有条目的值。但是如果.equals()返回false怎么办?在这种情况下,两个对象是不同的,应该作为单独的条目存储。因此,它们并排存放在同一个隔间中。因此,在检索值时,使用输入键的哈希代码到达存储它的隔室,然后如果隔室包含多个对象,则检查输入键是否与隔室中的每个对象相等,如果匹配,则返回相关值

现在,让我们将上述理论应用到您的代码中。如果字符串对象的内容相等,则它们相等。根据规则,如果两个对象相等,它们应该返回相同的哈希代码。但请记住,匡威不是真的。如果两个对象返回相同的哈希代码,则不要求它们相等。这在一开始似乎令人困惑,但您可以在几次迭代中克服它。两个具有相同内容的字符串是相等的,即使它们是物理上不同的对象,也返回相同的哈希代码,因此,当在hashmap中用作键时,它们将始终映射到相同的条目。这就是行为


String类重写默认的equals()方法,该方法表示,如果两个对象的引用与依赖于相等内容的对象的引用相同,则两个对象是相等的。它可以这样做,因为字符串是不可变的。但是,StringBuffer不会这样做。它仍然依赖于引用相等。

注意
sb1.equals(sb2)
是错误的,因为它们是完全不同的东西。字符串就是字符串。字符串生成器在你将其转换为字符串之前不是字符串。你能解释一下为什么你认为它们应该是相同的吗?造成这种不一致的确切区别是什么。两者都是内部字符[]。不是吗?字符串是不可变的,这意味着它不会改变。StringBuilder是可变的,这意味着仅仅因为两个StringBuilder现在恰好包含相同的文本,并不意味着它们将来会包含相同的文本。。。不,不是这样,这些字符串是不同的对象,因为它们是用
new
创建的,而不是interned。请自己尝试:
String a=“abc”;字符串b=“abc”;System.out.println(a==b)你应该自己试试。代码是
strings1=新字符串(“abc”),而不是
字符串a=“abc”。注意
new
的用法。哦,伙计,看看我贴的代码。我没有使用OP提供的。请阅读我在文章开头所说的内容。我现在明白了,尽管我不确定这如何适用于OPs问题,这归结为
StringBuilder
没有覆盖
equals
hashCode
。无论如何,很抱歉误读了。
public boolean equals(Object obj) {
    return (this == obj);
}
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String) anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                        return false;
                i++;
            }
            return true;
        }
    }
    return false;
}