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
EnumSetis an abstract class that has two main implementations:RegularEnumSet– Used when the enum has ≤ 64 values (stores elements in a singlelongbit field).JumboEnumSet– Used when the enum has > 64 values (stores elements in along[]array).
- Instead of storing separate objects,
EnumSetrepresents 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. 🚀