I have a class of which there may be many instances (on a mobile device), so I'm trying to minimize the size. One of my fields is a "DrawTarget" that indicates whether drawing operations are being ignored, queued to a path or drawn to the display. I would like it to take a single byte or less since there are only 3 possible values, but I would also like it to be friendly code so I don't have hard-coded numbers all over. One thought is to use an enum like:
public enum DrawTarget {
Invisible,
Path,
Canvas
}
But from what I read, a Java enum doesn't allow you to specify the memory layout -- I can't request that the enum values represent a byte-size value -- and I guess enum values end up being integer-sized values in Java.
So I thought about maybe making an implicit conversion operator in the enum... is this possible in Java? Or is my best option to implement something like this within the enum:
public static DrawTarget fromValue(byte value) {
switch (value) {
case 0:
return Invisible;
case 1:
return Path;
default:
return Canvas;
}
}
and then call DrawTarget.fromValue wherever I want to access the value?
Or should I just create a single-byte class since apparently (from what I read in my research on this) enums are basically just special classes in Java anyway?
public class DrawTarget {
public static final byte Invisible = 0;
public static final byte Path = 1;
public static final byte Canvas = 2;
}
But how to I represent the value of an enum instance if I use that last solution? I still need a way to allow the "=" operator to accept one of the static fields of the class... like a conversion constructor or an assignment operator overload.
I suspect, however, that any class object, being a reference type, will take more than a byte for each instance. Is that true?
This means that an enum reference costs as much as any other object reference, usually four bytes.
The size is four bytes because the enum is stored as an int . With only 12 values, you really only need 4 bits, but 32 bit machines process 32 bit quantities more efficiently than smaller quantities.
On an 8-bit processor, enums can be 16-bits wide. On a 32-bit processor they can be 32-bits wide or more or less. The GCC C compiler will allocate enough memory for an enum to hold any of the values that you have declared. So, if your code only uses values below 256, your enum should be 8 bits wide.
Default. The default is -fno-short-enums . That is, the size of an enumeration type is at least 32 bits regardless of the size of the enumerator values.
In Java enum is a class that has as many instances, as there are values. The instances are produced at class (enum) loading time. Each place where you use an enum variable or an enum attribute, you actually use an ordinary reference to one of the existing enum objects (instances of enums are never created after enum is initialized).
This means that an enum reference costs as much as any other object reference, usually four bytes. Which is really, really, really little.
You don't know how much memory does a byte take (really! remember that low level memory management includes plenty of padding!), so any "optimization" based on this will fail. On a given architecture a byte field might take as much memory as an integer field (because it might be faster that way).
If you want to write good Java, use enum. Really. The only good reason not to use enums, would be if you had a whole array of values, like: drawTargets[] = new DrawTarget[100000];
If you insist on microoptimizing, just use plain bytes and forget enums; public static final byte SOMETHING = 1;
is fine for making comparisons (and sucks for debugging).
I have written Android programs for a long time and have never seen such microoptimization pay off. Your case might be the one in a million, but I don't think it is.
Also, to make life simpler for all of us, please consider using Java conventions in Java code: enum instances and public final static fields should be names LIKE_THIS
, attributes likeThis
(not LikeThis
!).
and I guess enum values end up being integer-sized values in Java.
No, enums are always classes in Java. So if you have a field of type DrawTarget
, that will be a reference - either to null
or to one of the three instances of DrawTarget
. (There won't be any more instances than that; it's not like a new instance of DrawTarget
is created every time you use it.)
I would go with the enum and then measure the memory usage - an enum is logically what you want, so take the normal approach of writing the simplest code that works and then testing the performance - rather than guessing at where bottlenecks might be.
You may want to represent the value as a single byte when serializing, and then convert it back to the enum when deserializing, but other than that I'd stick with the enum type throughout your code if possible.
Unless android has some special way of treating enum references, each reference to a DropTarget will indeed take more than one byte in memory. Enums are classes, and enum instances are objects. So a reference to an enum instance takes the same amout of memory as any other object reference.
I wouldn't care much about it unless you have measured that this caused memory problems, though, and that reducing the size would have a significant impact.
What you get from enums, mainly, is type safety. If a method takes a DropTarget
as argument, you (or coworkers) won't be able to pass anything other than one of the three instances of DropTarget
(or null). If you use a byte instead, the code is less clear, and anyone could pass any byte value instead of the three authorized byte values.
So, decide which is the most important for you, and choose the solution you prefer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With