Reputation: 20658
I have this enum:
public enum Direction {
LEFT,
RIGHT,
ABOVE,
BELOW
}
Can I get and set a Direction
variable that contains 2 or more values, for example:
Direction fromDirection = Direction.LEFT + Direction.ABOVE
If it's possible, please tell me how to achieve it.
Upvotes: 1
Views: 2404
Reputation: 11
You can achieve that with some bitwise hacking. You can't get any faster process than this. EnumSet is slower in this case.
It basically converts enums to numbers and stores then in a single integer. Each byte of the integer represents if the enum is on or off. But there is one downside of it, you can't work with enums bigger than 32 values. Actually, you can, if you rework it to work with long values, allowing you to use up to 64 value enums.
This is a neat trick I use to store multiple boolean data into the database with the size of a single integer. Instead of making 32 columns each representing a single boolean, I can achieve it with 1 column representing the sum of all booleans. The only flaw of this is that you can't know which booleans are on/off with a single look.
public enum ENUM
{
AAA, SSS, DDD, FFF, GGG, HHH, JJJ, KKK, LLL, ZZZ, XXX, CCC;
public static int add(int addTo, ENUM val)
{
return addTo | (1 << val.ordinal());
}
public static int remove(int removeFrom, ENUM val)
{
return removeFrom & ~(1 << val.ordinal());
}
public static boolean contains(int in, ENUM val)
{
return (in & (1 << val.ordinal())) != 0;
}
}
public static void main(String[] args)
{
int enums = 0;
enums = ENUM.add(enums, ENUM.AAA);
enums = ENUM.add(enums, ENUM.SSS);
for (ENUM enu : ENUM.values())
if (ENUM.contains(enums, enu))
System.out.println(enu);
System.out.println("Operation 2.");
enums = ENUM.remove(enums, ENUM.AAA);
enums = ENUM.remove(enums, ENUM.KKK);
enums = ENUM.add(enums, ENUM.DDD);
for (ENUM enu : ENUM.values())
if (ENUM.contains(enums, enu))
System.out.println(enu);
}
The following result was printed:
AAA
SSS
Operation 2.
SSS
DDD
I will try to explain this in the simplest way possible.
val.ordinal() is the order number of the enum.
1 << val.ordinal() moves the bit with X spaces to the left. (because 1 = 00000000 00000000 00000000 00000001 in binary, you can move it max 31 times) Basically the enum order is the bit order in the integer. If the enum's order is 5, then it will be 1 << 5, whick means we move that 1 in the binary 5 times to the left. Resulting in 00000000 00000000 00000000 00100000.
result = addTo | enumNum This checks the location of the enum bit and sets it to 1 in the result integer. So if the enumNum is 00000000 00000000 00000000 00100000 for example and the result(addTo) is currently 00000000 00000000 00000000 00000001, it will become 00000000 00000000 00000000 00100001.
result = removeFrom & ~enumNum First, the '~' reverses the bit state. the enumNum 00000000 00000000 00000000 00100000 becomes 11111111 11111111 11111111 11011111. '&' Checks all bits and sets them to 0, unless the current bit of both integers is 1. So lets see 00000000 00000000 00000000 00100001 & 11111111 11111111 11111111 11011111 becomes 00000000 00000000 00000000 00000001, because the only pair of 1s is the rightest pair.
result & enumNum As I said above, all bits are turned to 0s, unless there is a pair of 1s. 00000000 00000000 00000000 00000001 & 00000000 00000000 00000000 00100000. There is no pair of 1s here, so looks like the result is =0. If we set the current result to 00000000 00000000 00000000 00100001 then we & 00000000 00000000 00000000 00100000 and we will get 00000000 00000000 00000000 00100000 as final result. The 5th bit pair is a pair of 1s, thats why it stays. The number returned is 2^5=32, which is != 0.
For more detailed information on how bitwise operations work, check here
Upvotes: 1
Reputation: 46183
You could use a java.util.EnumSet
:
final Set<Direction> northEast = EnumSet<Direction>.of(Direction.NORTH, Direction.EAST);
Of course, you could use any other set implementation, but EnumSet
types are implemented as bit vectors, very space and time efficient and probably the best built-in facility for your goal.
You may also want to define a static method in the enum type which checks for valid combinations.
Upvotes: 7
Reputation: 19185
You can also use
private static EnumSet<Direction> someDirection = EnumSet.of(Direction.LEFT,Direction.RIGHT) ;
Upvotes: 3
Reputation: 8197
Can I get and set a Direction variable that contains 2 or more values
You have already declared the type of Direction
as enum, if you try declaring it again as some variable, it will cause variable redefinition error.
Also Enums are constant and you cant reset there values later.
Upvotes: 0