2016-02-05 458 views
0

在此代码中,我声明了一个Initialized String变量,然后打印其哈希码,然后将其重新初始化为另一个值,然后调用垃圾收集器清除解除引用的对象。Java中String类的垃圾回收

但是,当我将字符串变量重新初始化为其原始值并打印哈希码时,将打印相同的哈希码。怎么样?

public class TestGarbage1 { 

    public static void main(String args[]) { 

     String m = "JAVA"; 
     System.out.println(m.hashCode());   
     m = "java"; 
     System.gc(); 
     System.out.println(m.hashCode()); 
     m = "JAVA"; 
     System.out.println(m.hashCode()); 
    } 
} 
+4

尽管Object的哈希码是从其内存地址派生而来的,但String的哈希码是从它的值派生而来的。 –

+3

尽管@ Elogent的评论,你有问*的GC,但一个不一定已经运行。 –

+0

即使GC在您调用'System.gc()'的行上立即发生,'m'仍然指向'“JAVA”',因此不会收集实例。 –

回答

2

我认为你误解了hashcode的工作原理。没有太多细节,在Java中,hashcode被用于很多事情。一个示例用于在Hash数据结构中查找项目,如HashMapHashSet

相同值的散列应始终返回相同的散列。在这种情况下,"JAVA"的哈希值应该永远不会改变,因为那样会破坏Java中提出的协议。

我认为这太复杂了,不知道字符串的hashcode是如何计算的。你可以阅读更多关于它here。我可以给你一个例子。

比方说,你有一个类Fruit它有像形状,颜色和重量领域。

您必须为此课程实施equalshashcode。做这两件事非常重要,否则你会打破Hashmap的工作方式。假设您为此采取hashCode()方法。

@Override 
public int hashCode() { 
    int hash = 1; 
    hash = hash * 17 + this.color; 
    hash = hash * 31 + this.shape.hashCode(); 
    hash = hash * 31 + this.weight; 
    return hash; 
} 

这将为两个相等的Fruit实例生成相同的散列值。这正是你想要的。

真的很快,这将如何实际用于HashMap?假设你想看看你是否有foo = new Fruit(); HashMap首先计算foo.hashCode()。它检查是否存在该hashCode的桶中的任何内容。如果有,那么它将使用equals()方法,直到它返回true。它必须这样做,因为可能存在散列码冲突。这就是为什么equals和hashCode应该一起实现是很重要的原因。

3

哈希码涉及对象的相等性,而不是身份。

a.equals(b) implies a.hashCode() == b.hashCode() 

(提供的两个方法已经持续实施)

即使GC实际上是发生在这里(和你不能简单地引用常量池中的字符串),你不会指望两个具有相同字符序列的字符串实例不相等 - 因此,它们的哈希码也是相同的。

String a = new String("whatever"); 
String b = new String(a); 
System.out.println(a == b); // false, they are not the same instance 
System.out.println(a.equals(b)); // true, they represent the same string 
System.out.println(a.hashCode() == b.hashCode()); // true, they represent the same string 
+0

好奇,如果他使用'System.identityHashCode(Object)'会打印一个不同的值。我不认为这会归因于Java中的String interning。 –