我怎么能确定我的班级是不可变的

时间:2014-02-01 00:57:30

标签: java string hashmap hashcode

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

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

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

3 个答案:

答案 0 :(得分:2)

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

this.bytes = passedInArray;

调用者可以修改passInArray,从而修改this.bytes。你必须

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

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

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

答案 1 :(得分:2)

你的问题是"我怎样才能确定我的班级是不可改变的?"我不确定你的意思是什么,但是Josh Bloch在 Effective Java,2nd Ed。第15项中列出了使你的类不可变的方法{{ 3}},我将在这个答案中总结:

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

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

答案 2 :(得分:0)

  

因为不可变对象在哈希映射中执行更快的搜索。 (我想请一个这个事实的来源)

不,这不是真的。作为hashmap键的性能将由hashCode的运行时和冲突避免决定。

  

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

您的问题更有可能成为hashCode实施的糟糕选择。考虑将您的实施基于Arrays.hashCode

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