7

(モバイルデバイス上で)多くのインスタンスが存在する可能性のあるクラスがあるため、サイズを最小化しようとしています。私のフィールドの1つは、描画操作が無視されているか、パスにキューに入れられているか、ディスプレイに描画されているかを示す「DrawTarget」です。可能な値は3つしかないので、1バイト以下にしたいのですが、ハードコードされた数値がないように、わかりやすいコードにしたいのです。1つの考えは、次のような列挙型を使用することです。

public enum DrawTarget {
    Invisible,
    Path,
    Canvas
}

しかし、私が読んだところによると、Java列挙型ではメモリレイアウトを指定できません-列挙型の値がバイトサイズの値を表すように要求することはできません-列挙型の値は最終的に整数サイズの値になると思いますJavaで。

だから私はおそらく列挙型で暗黙の変換演算子を作ることを考えました...これはJavaで可能ですか?または、列挙型内にこのようなものを実装するための私の最良のオプションです:

public static DrawTarget fromValue(byte value) {
    switch (value) {
    case 0:
        return Invisible;
    case 1:
        return Path;
    default:
        return Canvas;
    }
}

次に、値にアクセスしたい場所でDrawTarget.fromValueを呼び出しますか?

それとも、(これに関する私の研究で読んだことから)列挙型は基本的にJavaの特別なクラスであるため、シングルバイトクラスを作成する必要がありますか?

public class DrawTarget {
    public static final byte Invisible = 0;
    public static final byte Path = 1;
    public static final byte Canvas = 2;
}

しかし、最後のソリューションを使用する場合、列挙型インスタンスの値をどのように表すのですか?「=」演算子がクラスの静的フィールドの1つを受け入れることができるようにする方法がまだ必要です...変換コンストラクターや代入演算子のオーバーロードなど。

ただし、参照型であるクラスオブジェクトは、インスタンスごとに1バイト以上かかると思います。本当?

4

5 に答える 5

11

Java enum では、値と同じ数のインスタンスを持つクラスです。インスタンスは、クラス (enum) の読み込み時に生成されます。enum 変数または enum 属性を使用する各場所では、実際には既存の enum オブジェクトの 1 つへの通常の参照を使用します (enum の初期化後に enum のインスタンスが作成されることはありません)。

これは、列挙参照のコストが他のオブジェクト参照と同じで、通常は 4 バイトであることを意味します。これは本当に、本当に、本当に少しです。

  1. 1 バイトがどれだけのメモリを消費するかはわかりません (本当に! 低レベルのメモリ管理には多くのパディングが含まれていることを思い出してください!)、これに基づく「最適化」は失敗します。特定のアーキテクチャでは、バイト フィールドは整数フィールドと同じくらい多くのメモリを使用する場合があります (その方が高速である可能性があるため)。

  2. 良い Java を書きたい場合は、enum を使用してください。本当。列挙型を使用しない唯一の正当な理由は、次のような値の配列全体がある場合です。drawTargets[] = new DrawTarget[100000];

  3. マイクロ最適化を主張する場合は、単純なバイトを使用し、列挙型を忘れてください。public static final byte SOMETHING = 1;比較を行うには問題ありません(デバッグには適していません)。

私は長い間 Android プログラムを書いてきましたが、そのようなマイクロ最適化が功を奏したことはありません。あなたのケースは 100 万分の 1 かもしれませんが、そうではないと思います。

LIKE_THISまた、私たち全員の生活をよりシンプルにするために、Java コードで Java 規則を使用することを検討してlikeThisください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

クラスには、列挙型への参照のみが含まれます。各列挙型の 1 つのインスタンスのみが作成されます。

それとは別に、ポリモーフィズムを使用して描画動作を実装することを検討してください。

列挙型の値が固定されている場合は、目的の描画動作に応じて、オブジェクトごとに異なるサブクラスをインスタンス化します。

値が頻繁に変更される場合は、目的の描画戦略への参照をオブジェクトに保持できます。描画してはいけないオブジェクトについては、 draw() メソッドが空のオブジェクトを参照してください。等。

于 2013-03-03T13:30:14.027 に答える