包含自身作为元素的 ArrayList 的哈希代码



我们能找到包含自身作为elementlisthashcode吗?

我知道这是一种不好的做法,但这是面试官问的。

当我运行以下代码时,它会抛出一个StackOverflowError

public class Main {
public static void main(String args[]) {
ArrayList<ArrayList> a = new ArrayList();
a.add(a);
a.hashCode();
}
}

现在我有两个问题:

  1. 为什么会有StackOverflowError
  2. 是否可以以这种方式找到哈希代码?

接口中指定了用于符合List实现的哈希代码:

返回此列表的哈希代码值。 列表的哈希代码 定义为以下计算的结果:

int hashCode = 1;
for (E e : list)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

这确保了list1.equals(list2)意味着list1.hashCode()==list2.hashCode()任何两个列表,list1list2,如Object.hashCode()总合同的要求。

这并不要求实现看起来完全像这样(请参阅如何以与 List.hashCode(( 相同的方式计算流的哈希代码以获取替代方案(,但仅包含自身的列表的正确哈希代码将是必须truex == 31 + x的数字,换句话说,不可能计算出符合要求的数字。

查看AbstractList类中hashCode方法的骨架实现。

public int hashCode() {
int hashCode = 1;
for (E e : this)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
return hashCode;
}

对于列表中的每个元素,这将调用hashCode。在您的案例列表中,列表本身是唯一的元素。现在这个电话永远不会结束。该方法递归地调用自己,递归不断缠绕,直到遇到StackOverflowError。所以你不能用这种方式找到hashCode

您已经定义了一个包含自身的(病理(列表。

为什么会有StackOverflowError

根据javadocs(即规范(,List的哈希码被定义为其每个元素的哈希码的函数。 它说:

"列表的哈希代码定义为以下计算的结果:">

int hashCode = 1;
for (E e : list)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

所以要计算a的哈希码,你首先要计算a的哈希码。 这是无限递归的,并迅速导致堆栈溢出。

可以通过这种方式找到哈希代码吗?

不。 如果你用数学术语来考虑上面的算法规范,那么包含自身的List的哈希码是一个不可计算的函数。 不可能以这种方式(使用上述算法(或任何其他方式计算它。

不,文档有答案

列表结构的文档明确指出:

注意:虽然允许列表将自身作为元素包含,但建议格外小心:在这样的列表中不再很好地定义 equals 和 hashCode 方法。

除此之外,没有什么可说的了 - 根据Java规范,您将无法计算包含自身的列表的hashCode;其他答案详细说明了为什么会这样,但关键是它是已知的和有意的。

Ravindra的回答为第1点提供了很好的解释。对问题2发表评论:

是否可以以这种方式找到哈希代码?

这里有一些循环的东西。在此堆栈溢出错误的上下文中,这 2 个中至少有一个必须错误:

列表的哈希代码
  • 必须考虑其元素的哈希代码
  • 列表可以成为自己的元素

现在,因为我们在处理一个ArrayList,所以第一点是固定的。换句话说,也许你需要一个不同的实现来有意义地计算递归列表的哈希代码......可以扩展ArrayList并跳过添加元素的哈希代码,例如

for (E e : this)
if(e == this) continue; //contrived rules
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

使用这样的类而不是ArrayList,你可以。

对于ArrayList,第二点是错误的。因此,如果面试官的意思是"是否有可能以这种方式(使用数组列表(找到哈希代码?">,那么答案是否定的,因为这很荒谬。

因为当你从同一个函数调用同一个函数时,它将创建永无止境的递归条件。为了防止此操作,JAVA 将返回java.lang.StackOverflowError

下面是解释类似场景的示例代码:

public class RefTest {
public static void main(String... strings) {
RefTest rf = new RefTest();
rf.message(message("test"));
}
public static String message2(String s){
return message(s);
}
public static String message(String s){
return message2(s);
}
}   

相关内容

最新更新