7

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?

4

5 回答 5

11

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.

  1. 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).

  2. 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];

  3. 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!).

于 2013-03-03T13:33:14.217 回答
3

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.

于 2013-03-03T13:24:49.593 回答
3

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.

于 2013-03-03T13:25:04.247 回答
1

Your classes will only contain a reference to the enum. Only one instance of each enum will be created.

Aside from that, consider using polymorphism to implement the drawing behavior.

If the value of the enum is fixed, instantiate a different subclass for each object depending on its desired drawing behavior.

If the value changes often, you could keep a reference to the desired drawing strategy in the object. Refer to an object with an empty draw() method for objects that should not be drawn. Etc.

于 2013-03-03T13:30:14.027 回答
0

enum is special data type, not a class.check oracle documentations for further details. An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it.

于 2013-05-14T09:53:58.333 回答