How EnumSet
Stores Data Internally in Java
Unlike HashSet
, which stores elements using a hash table (creating separate objects for each element), EnumSet
stores enum values as bitwise flags inside a single long
or long[]
array, making it much more memory-efficient and faster.
1️⃣ How EnumSet
Works Internally
EnumSet
is an abstract class that has two main implementations:RegularEnumSet
– Used when the enum has ≤ 64 values (stores elements in a singlelong
bit field).JumboEnumSet
– Used when the enum has > 64 values (stores elements in along[]
array).
- Instead of storing separate objects,
EnumSet
represents each enum constant as a bit in a bitmask.
2️⃣ How RegularEnumSet
Works (For ≤ 64 Enum Constants)
For enums with ≤ 64 elements, EnumSet
uses a single long
(64-bit field) to store the enum values.
Example: Enum with 3 Constants
import java.util.EnumSet;
enum Color { RED, GREEN, BLUE }
public class EnumSetExample {
public static void main(String[] args) {
EnumSet<Color> colors = EnumSet.of(Color.RED, Color.BLUE);
System.out.println(colors); // Output: [RED, BLUE]
}
}
How Is It Stored Internally?
- Java assigns an ordinal value to each enum constant:
RED = 0
GREEN = 1
BLUE = 2
EnumSet
represents them as bits in a long
:
RED = 1 << 0 (0001 in binary)
GREEN = 1 << 1 (0010 in binary)
BLUE = 1 << 2 (0100 in binary)
The set {RED, BLUE}
is stored as:
0001 (RED)
0100 (BLUE)
EnumSet
Bitwise Representation Example
EnumSet
internally uses bitwise operations to store and manipulate enum values efficiently.
1️⃣ Understanding Bitwise Representation
Each enum constant has an ordinal value (its position in the enum
declaration). EnumSet
stores the set as a bitmask, where each bit represents an enum constant.
Example Enum
enum Color {
RED, // ordinal = 0
GREEN, // ordinal = 1
BLUE, // ordinal = 2
YELLOW // ordinal = 3
}
EnumSet
represents each enum constant as a bit at the position of its ordinal value:
RED = 1 << 0 → 0001 (binary) = 1 (decimal)
GREEN = 1 << 1 → 0010 (binary) = 2 (decimal)
BLUE = 1 << 2 → 0100 (binary) = 4 (decimal)
YELLOW = 1 << 3 → 1000 (binary) = 8 (decimal)
2️⃣ Creating an EnumSet
and Checking Internal Representation
Let’s create an EnumSet
and see how it is stored internally.
Example: Creating an EnumSet
import java.util.EnumSet;
public class EnumSetBitwiseExample {
public static void main(String[] args) {
EnumSet<Color> colors = EnumSet.of(Color.RED, Color.BLUE);
int bitmask = getBitmask(colors);
System.out.println("Bitmask: " + Integer.toBinaryString(bitmask)); // Print bitwise representation
}
private static int getBitmask(EnumSet<Color> set) {
int mask = 0;
for (Color c : set) {
mask |= (1 << c.ordinal()); // Bitwise OR operation
}
return mask;
}
}
Output
Bitmask: 101
Explanation
{RED, BLUE}
corresponds to bit positions 0 and 2.- Bitwise OR (
|
) is used to set the bits
RED → 0001 (1 in decimal)
BLUE → 0100 (4 in decimal)
---------------------------
Combined (RED | BLUE) = 0101 (5 in decimal)
The output 101
(binary) confirms that RED
(1st bit) and BLUE
(3rd bit) are set.
3️⃣ Bitwise Operations in EnumSet
Adding an Element (Bitwise OR |
)
If we add GREEN
to {RED, BLUE}
, it updates the bitmask:
colors.add(Color.GREEN);
New Bitmask Calculation
RED = 0001 (1)
BLUE = 0100 (4)
GREEN = 0010 (2)
-----------------
Result = 0111 (7)
✔ New Bitmask: 7
(0111
in binary) → {RED, GREEN, BLUE}
.
Removing an Element (Bitwise AND & Complement & ~
)
If we remove RED
, we update the bitmask:
colors.remove(Color.RED);
Current Set: 0111 (7) → {RED, GREEN, BLUE}
Remove RED: ~0001 (NOT 1)
----------------------
New Bitmask: 0110 (6) → {GREEN, BLUE}
✔ New Bitmask: 6
(0110
in binary) → {GREEN, BLUE}
.
4️⃣ Why Is This Efficient?
- Takes only 1
long
(64 bits) to store up to 64 enums. - Bitwise operations (
|
,&
,~
) are extremely fast (O(1)
complexity). - No hashing overhead like
HashSet
.
📌 Conclusion:EnumSet
uses bitwise operations internally to efficiently store, add, and remove elements. Instead of storing separate objects, it uses a single integer (long
) as a bitmask to track which enums are in the set. 🚀