How can I be sure that my class is immutable
我需要创建一个与 String 非常相似的类,但是该对象必须存储一个字节数组,而不是存储一个字符数组,因为我将处理二进制数据,而不是字符串。
我在我的应用程序中使用 HashMaps。因此,我热衷于使我的自定义 byteArray 类不可变,因为不可变对象在哈希图中执行更快的搜索。 (我想要这个事实的来源)
我很确定我的类是不可变的,但它在 hashmap 搜索中与字符串相比仍然表现不佳。我如何确定它是不可变的?
- 将其字段设为 final。如果任何字段属于数组类型,请不要让它们可访问(对于任何其他可变引用类型也是如此)。
-
为什么哈希图中的不可变对象如此有效? stackoverflow.com/questions/10342859/…
-
上面的评论很好。您应该查看问题答案的代码。它回答了为什么字符串更快。你应该在你的代码中做同样的事情来提高性能。
-
那么如何在类上"在计算一次后缓存哈希"?还是自定义类无法使用此功能
-
它不是 Java 功能,它是您可以自己编写的东西,也是 String 的作者自己编写的东西。所有类都是自定义类。
-
一定有我想要的课程已经写好了,对吧?封装的字节数组而不是封装的字符数组,如 String
-
您需要编写一个自定义 hashCode() 来缓存计算后的哈希,请参阅@alex 的链接
-
如果没有办法从类外部修改它的内部,它是不可变的(或者在 Java 中尽可能接近)。
您的问题是"我如何确定我的类是不可变的?"我不确定这就是您要问的意思,但是 Josh Bloch 在 Effective Java, 2nd Ed 中列出了使您的类不可变的方法。在此处的第 15 项中,我将在此答案中进行总结:
不要提供任何 mutator 方法(改变对象状态的方法,通常称为"setter")。
确保类不能扩展。通常,使类最终。这可以防止其他人对其进行子类化并修改受保护的字段。
将所有字段设为最终字段,因此您无法更改它们。
将所有字段设为私有,以便其他人无法更改它们。
"确保对可变组件的独占访问。"也就是说,如果有其他东西指向数据并因此可以更改它,请制作一个防御性副本(正如@user949300 指出的那样)。
请注意,不可变对象不会自动产生巨大的性能提升。不可变对象的好处在于不必锁定或复制对象,以及重用它而不是创建一个新对象。我相信 HashMap 中的搜索使用类的 hashCode() 方法,并且查找应该是 O(c),或者恒定时间和快速。如果您遇到性能问题,您可能需要查看您的 hashCode() 方法是否存在缓慢(不太可能)或其他问题。
一种可能性是,如果您的 hashCode() 实现不佳(或根本没有实现),这会导致您的 HashMap 中出现大量冲突——也就是说,使用您的类的不同实例调用该方法主要返回相似或相同的值——那么实例将存储在 hashCode() 指定位置的链表中。遍历此列表会将您的效率从恒定时间转换为线性时间,从而使性能变得更差。
-
#4是不必要的(如果你这样做#3),否则所有优点。
-
@user949300 没错,Bloch 同意你的观点,尽管他继续指出,将字段设为私有是一种最佳做法,这样你就可以在以后更改它们的内部表示。
最重要的是将字节复制到您的数组中。如果你有
this.bytes = passedInArray;
调用者可以修改passedInArray,从而修改this.bytes。你必须这样做
this.bytes = Arrays.copyOf(passedInArray, passedInArray.length);
(或类似的,克隆也可以)。如果这个类主要用作 Maps 中的键,我会立即(在构造函数中)计算哈希码,比懒惰地计算更简单。
实现明显的 equals() 我认为你已经完成了。
- 我一直在用 .clone() 这个是一样的吗?啊,所以你说在构造函数中调用 myHashCode() 方法来更新最终的 int hashCode 字段。那么在 hashCode() 覆盖的方法中我可以只返回 hashCode 字段吗?
-
是的,克隆应该没问题。 (不得不承认,我避免克隆导致它在许多情况下使用起来更难/棘手)。是的,在构造函数中调用 myHashCode 并设置一个 final 字段。
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[] 的建议很好。)
-
感谢您的回答和澄清。我写了一个字节数组package器。我的哈希码方法读取: hashCode() { return Arrays.hashCode(byteArray);我可以想象这会导致更多的冲突,因为字节已签名。