7

4文字のセットを使用して「意味」を持つ整数を形成するバイナリファイルがあります。たとえば'0005'、整数形式の808464437に等しい4バイト。

これらをJavaコード'0005'で808464437ではなく表現したいと思います。また、のような定数を設定したくありませんfinal int V0005 = 808464437

C ++では、次のことができます。

fileStream->read((byte*) &version, 4); //Get the next bytes and stuff them into the uint32 version

switch (version) {
    case '0005':
        //do something
    case '0006':
        //do something
    case '0007':
        //do something
}

Javaでは、私の問題は4バイトを読み取って、それらを何らかのデータ型に入れることではありません。私の問題は、いくつかのデータ型をconstchar配列と比較すること'0005'です。

'0005'intまたはその他の形式をJavaのようなconst文字配列と比較するにはどうすればよいですか?私はこれをできるだけ効率的に行う必要があります!

4

7 に答える 7

4

あなたの答えを説明してくれてありがとう。

4バイトからintに変換する方法は次のとおりです。これを、問題のintと比較できます。

    int v0005 = ByteBuffer.wrap("0005".getBytes()).asIntBuffer().get();

残念ながら、これは私がそれを行うために見ることができる唯一の方法です...おそらくあなたが望むほど効率的ではありませんが、それでもおそらくそれはあなたが必要とするものです。

次のように、クラスの1つでこれらのいくつかを「定数」として設定することをお勧めします。

public static final int V0005 = ByteBuffer.wrap("0005".getBytes()).asIntBuffer().get();
public static final int V0006 = ByteBuffer.wrap("0006".getBytes()).asIntBuffer().get();
public static final int V0007 = ByteBuffer.wrap("0007".getBytes()).asIntBuffer().get();
public static final int V0008 = ByteBuffer.wrap("0008".getBytes()).asIntBuffer().get();

そして、プリミティブ型(int)をオンにすると効率的であるため、V0005などをオンにします。

于 2013-02-22T19:47:09.057 に答える
3

javaのchar配列は、javaのaStringにすぎません。Java7のスイッチケースで文字列を使用できますが、比較の効率はわかりません。

char配列の最後の要素だけが意味を持っているように見えるので、それを使ってswitchcaseを実行できます。何かのようなもの

private static final int VERSION_INDEX = 3;

...
    char[] version = // get it somehow

    switch (version[VERSION_INDEX]) {
         case '5': 
            break;
         // etc
    }
...

より多くのオブジェクト指向バージョンを編集します。

  public interface Command {
       void execute();
  }

  public class Version {
       private final Integer versionRepresentation;

       private Version (Integer versionRep) {
            this.versionRepresentation = versionRep;
       }

       public static Version get(char[] version) {
            return new Version(Integer.valueOf(new String(version, "US-ASCII")));
       }

       @Override
       public int hashCode() {
            return this.versionRepresentation.hashCode();
       }
       @Override
       public boolean equals(Object obj) {
            if (obj instanceof Version) {
                Version that = (Version) obj;

                return that.versionRepresentation.equals(this.versionRepresentation);
            }
            return false;
       }
  }

  public class VersionOrientedCommandSet {
       private final Command EMPTY_COMMAND = new Command() { public void execute() {}};
       private final Map<Version, Command> versionOrientedCommands;

       private class VersionOrientedCommandSet() {
           this.versionOrientedCommands = new HashMap<Version, Command>();
       }

       public void add(Version version, Command  command) {
           this.versionOrientedCommands.put(version, command);
       }

       public void execute(Version version) throw CommandNotFoundException {
           Command command = this.versionOrientedCommands.get(version);

           if (command != null)  {
               command.execute();
           } else {
               throw new CommandNotFoundException("No command registered for version " + version);
           }

       }
  }

  // register you commands to VersionOrientedCommandSet
  char[] versionChar = // got it from somewhere
  Version version = Version.get(versionChar);
  versionOrientedCommandSet.execute(version);

多くのコードheheウォームアップには少しコストがかかりますが、プログラムを複数回実行すると、マップで効率が向上します:P

于 2013-02-22T19:44:36.097 に答える
2

他のいくつかの答え(@marvoと@vikingsteve)から少し得て、私はこれを思いついた:

public enum Version {

  V0005 {

    @Override
    public void doStuff() {
      // do something
    }
  },
  V0006 {
  @Override
    public void doStuff() {
    // do something else
    }

  };

private final int value;
private static final Map<Integer, Version> versions = new HashMap<>();

private Version() {
    final byte[] bytes = name().substring(1).getBytes(); //remove the initial 'V'
    this.value = ByteBuffer.wrap(bytes).asIntBuffer().get();
}

static {
    for (Version v : values()) {
        versions.put(v.value, v);
    }
}

public abstract void doStuff();


public Version valueOf(int i){
    return versions.get(i);
}
}

アクションはデータ表現でカプセル化されるため、これは優れたオブジェクト指向アプローチを提供します。各定数は、doStuffが呼び出されたときに何をするかを決定し、クライアントコードのスイッチを回避します。使用法は次のようになります:

int code = readFromSomewhere();
Version.valueOf(i).doStuff();

このメソッドは、クラスのロード時に入力されるマップ内でをvalueOf検索します。Versionこれがあなたが必要とするほど効率的であるかどうかはわかりません。なぜなら、intはボックス化されているからですが、プロファイルを作成したときにIntegerのみわかります。他のすべては純粋な推測です。また、整数値はコンストラクターで計算されるためenums、正しい名前でを定義するだけで、自動的に実行されることに注意してください。

于 2013-02-23T00:02:33.110 に答える
1

唯一の方法は、非常に非効率的なbyte[]からStringへの変換です。

switch (new String(version, "US-ASCII")) {
case "0005":
    break;
...
}

代わりに(ハッシュ)マップを使用すると、再び高速になります。

しかし、私はあなたがこの解決策に満足しないだろうと思います。

于 2013-02-22T19:49:08.060 に答える
1

これがパケットなどのバージョン文字列であるように見える場合、値の数は有限であり、妥当な量です。したがって、列挙型にカプセル化できます。列挙型は、入力データの4バイトから代表的な列挙型に変換するための効率的なコードをカプセル化できます。(その変換を実行するための私のコードは、必ずしも最も効率的ではありません。バージョンの数が少ない場合は、内部配列またはintからenumへのマッピングが機能する可能性があります。)

class enum Version {

    UNKNOWN(0),
    V0005(0x30303035),  // whatever the int value is
    V0006(0x30303036);

    private int id;
    private Version(int value) {
        id = value;
    }

    public static Version valueOf(int id) {
        for (Version version : values()) {
            if (version.getId() == id) {
                return version;
            }
        }
        return UNKNOWN;
    }

    public static Version valueOf(String sId) {
        return valueOf(computeId(sId));
    }

    public static int computeId(String sId) {
        // efficiently convert from your string to its int value
    }
}

それから私のスイッチで:

String s = methodThatReadsFourChars(...);
switch (Version.valueOf(s)) {
case V0005 : doV0005Stuff(); break;
case V0006 : doV0006Stuff(); break;
default :
    throw new UnknownVersionException();
于 2013-02-22T20:44:21.880 に答える
1

あなたはのようなものを探していますvalue1.intValue() == value2.intValue()か?または、キャストと入力することもできます。

char myChar = 'A';
int myInt = (int) myChar;

同じ杖が逆に行きます。

int myInt = 6;
char myChar = (char) myInt;
于 2013-02-22T19:43:56.350 に答える
1

最も効率的な方法は、整数を操作することです。finalint V0005 = 0x30303035(ここで見られるいくつかの異なるアイデアの組み合わせ)のようなものは管理可能です。Javaには、探している種類の整数リテラルがありません。

本当に文字列を操作したい場合は、最初にバイト配列の文字を読み取り、それを文字列に変換する必要があります(デフォルトの文字セットはASCIIのスーパーセットであるため、通常は機能します)。ただし、効率は低下します。

読みやすくするために、単純な数値(5など)から定数値を計算する関数を作成することもできますが、それはおそらくやり過ぎです。

于 2013-02-22T19:56:46.720 に答える