关于java:如何确定我的类是不可变的

How can I be sure that my class is immutable

我需要创建一个与 String 非常相似的类,但是该对象必须存储一个字节数组,而不是存储一个字符数组,因为我将处理二进制数据,而不是字符串。

我在我的应用程序中使用 HashMaps。因此,我热衷于使我的自定义 byteArray 类不可变,因为不可变对象在哈希图中执行更快的搜索。 (我想要这个事实的来源)

我很确定我的类是不可变的,但它在 hashmap 搜索中与字符串相比仍然表现不佳。我如何确定它是不可变的?


您的问题是"我如何确定我的类是不可变的?"我不确定这就是您要问的意思,但是 Josh Bloch 在 Effective Java, 2nd Ed 中列出了使您的类不可变的方法。在此处的第 15 项中,我将在此答案中进行总结:

  • 不要提供任何 mutator 方法(改变对象状态的方法,通常称为"setter")。
  • 确保类不能扩展。通常,使类最终。这可以防止其他人对其进行子类化并修改受保护的字段。
  • 将所有字段设为最终字段,因此您无法更改它们。
  • 将所有字段设为私有,以便其他人无法更改它们。
  • "确保对可变组件的独占访问。"也就是说,如果有其他东西指向数据并因此可以更改它,请制作一个防御性副本(正如@user949300 指出的那样)。
  • 请注意,不可变对象不会自动产生巨大的性能提升。不可变对象的好处在于不必锁定或复制对象,以及重用它而不是创建一个新对象。我相信 HashMap 中的搜索使用类的 hashCode() 方法,并且查找应该是 O(c),或者恒定时间和快速。如果您遇到性能问题,您可能需要查看您的 hashCode() 方法是否存在缓慢(不太可能)或其他问题。

    一种可能性是,如果您的 hashCode() 实现不佳(或根本没有实现),这会导致您的 HashMap 中出现大量冲突——也就是说,使用您的类的不同实例调用该方法主要返回相似或相同的值——那么实例将存储在 hashCode() 指定位置的链表中。遍历此列表会将您的效率从恒定时间转换为线性时间,从而使性能变得更差。


    最重要的是将字节复制到您的数组中。如果你有

    this.bytes = passedInArray;

    调用者可以修改passedInArray,从而修改this.bytes。你必须这样做

    this.bytes = Arrays.copyOf(passedInArray, passedInArray.length);

    (或类似的,克隆也可以)。如果这个类主要用作 Maps 中的键,我会立即(在构造函数中)计算哈希码,比懒惰地计算更简单。

    实现明显的 equals() 我认为你已经完成了。


    since immutable objects perform faster searches in hashmaps. (I would like a source for this fact please)

    不,这不是真的。作为 hashmap 键的性能将由 hashCode.

    的运行时和冲突避免确定

    I'm pretty sure my class is immutable, but its still performing poorly vs string in hashmap searches. How can I be sure it is immutable?

    您的问题更可能是 hashCode 实现的错误选择。考虑将您的实现基于 Arrays.hashCode.

    (您的问题 ArrayList vs String in Java 表明您正在尝试调整特定的实现;使用 byte[] 的建议很好。)