3

I have recently been trying to implement a simple genetic algorithm. I need to use an inversible map which stores pairs of (Character,4 bits). I chose Guava's BiMap for this task. However tests will not pass because of an int array which I chose for the bits storage.

Is int[] a primitive type? Would the use of a Vector or List of integers be a more appropriate tool for this task?

Jonny Henly
  • 4,023
  • 4
  • 26
  • 43
don_pablito
  • 382
  • 1
  • 9

2 Answers2

5

Your problem is not that int[] is a primitive. An array in Java is an object. The problem is that it is an object which does not override the hashCode() and equals() methods.

Since it doesn't override them, they are the same as those of Object, where objects are equal only if they are identical (i.e. references to the same instance).

Basically:

int[] a = new int[] {1,1,1,1};
int[] b = new int[] {1,1,1,1};
System.out.println( a.equals(b) );

You are probably expecting this to print true, but it will print false, because you created two distinct arrays, and it checks whether the arrays are the same object, not whether their content is the same!

In all probability, if you also add

System.out.println( a.hashCode() );
System.out.println( b.hashCode() );

You'll also get two different hash codes.

For this reason, arrays are not very suitable to use in collections that check for equality/uniqueness. They are good as the value in a standard Map, but not as the key. And in a Guava BiMap they can be used for neither key nor value.

What should you do?

You should use an object which overrides the equals() and hashCode() so that if the contents are the same, equals() returns true and the same value is returned from hashCode() on both.

If you want something relatively compact, you can represent the bits with a Byte object. You can use bit manipulation operators with it.

Or you can use a BitSet which is a Java standard container for bits.

Be careful, as BitSet is mutable. Mutable objects might not behave well when used in value-sensitive data structures like hash tables, because most implementations can't tell when you changed the value and so they can't move it around in the hash buckets accordingly. Don't set or clear any bits in the object once it is stored in the BiMap!

RealSkeptic
  • 33,993
  • 7
  • 53
  • 79
  • Thank you very much for exhaustive answer. I also would like to ask: would encoding bits as String be considered as bad programming practice? – don_pablito Jul 11 '15 at 20:57
  • Personally, I would prefer `BitSet`. `String` would be wasteful, allow values that are not bits, and the usage will be less obvious to anybody reading the code. – RealSkeptic Jul 11 '15 at 21:17
  • See also Guava's [Equivalence](http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Equivalence.html), which effectively lets you provide custom `equals()`/`hashCode()` implementations for anything. – Tavian Barnes Jul 11 '15 at 23:14
  • @paffciu I'd go for a `Byte` (or `Integer`) as it's more than big enough for your 4 bits. It's a bit low-level, but `BitSet` is mutable, which means you can run into funny hard to debug problems when you modify it by accident. Your own class wrapping a `BitSet` or a `boolean[]` would be probably best as long as speed doesn't matter (most of the time it doesn't). – maaartinus Jul 12 '15 at 15:04
  • @maaartinus its my own project, i care only about learning what genetic algorithms is all about, so performance will be my target later :) – don_pablito Jul 13 '15 at 12:02
2

Is int[] primitive type?

No. Java arrays are not primitive types, even when their individual elements are primitive.

Will using vector or list of integers be appropriate tool for such task?

Neither Vector<T> nor List<T> could store primitives without "boxing" them into wrappers. However, if you need only four bits, you could use a single byte, which has eight bits available for storage.

To extract a bit k from a byte, use (b & (1 << k)) != 0 expression. When this expression evaluates to true, bit k is set to 1; otherwise, it is set to 0.

To set a bit k in a byte to 1, use b |= (1 << k). To reset bit k to 0 use b &= ~(1 << k)

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Thank you very much. I still have to store those bits in Map. In that case byte won't be appropriate, will it? – don_pablito Jul 11 '15 at 19:56
  • @paffciu Correct. You would need to use some other way of doing the map. I think Guava has some Java containers that store primitives, but I am not sure which ones. – Sergey Kalinichenko Jul 11 '15 at 20:01