7

我有一个二进制文件,它使用 4 个字符集来形成具有“意义”的整数。例如 4 个字节'0005',它等于整数形式的 808464437。

我宁愿在我的 Java 代码中将这些表示为808464437,'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 个字节并将它们放入某种数据类型。我的问题是将某些数据类型与 const char array 进行比较'0005'

如何将 int 或任何形式与'0005'Java 中的 const 字符数组进行比较?我需要尽可能有效地做到这一点!

4

7 回答 7

4

感谢您解释您的答案。

以下是将 4 个字节转换为 int 的方法,然后您可以将其与相关 int 进行比较:

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

不幸的是,这是我能看到的唯一方法......可能没有你想要的那么高效,但也许它仍然是你需要的。

我建议在您的一个类中将其中一些设置为“常量”,如下所示:

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();

然后打开 V0005 等,因为打开原始类型 (int) 是有效的。

于 2013-02-22T19:47:09.057 回答
3

java中的char数组只不过是Stringjava中的a。您可以在 Java7 的 switch-case 中使用字符串,但我不知道比较的效率。

因为只有你 char 数组的最后一个元素似乎有意义,所以你可以用它做一个 switch case。就像是

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);

大量的代码 呵呵 你会有一点热身成本,但如果你的程序被执行多次,你将获得地图的效率: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你只会在你 profile 时发现,其他一切都是纯粹的猜测。另请注意,整数值是在构造函数中为您计算的,因此您只需enums使用正确的名称定义 ,它将自动完成。

于 2013-02-23T00:02:33.110 回答
1

最有效的方法是使用整数 - 像 final int V0005 = 0x30303035 (这里看到的几个不同想法的组合)这样的东西是可以管理的。Java 只是没有您正在寻找的那种整数文字。

如果您真的想使用字符串,则需要先读取字节数组中的字符,然后将其转换为字符串(默认字符集通常可以工作,因为它是 ASCII 的超集)。但是,它的效率会更低。

您可以编写一个函数来从简单的数字(如 5)中计算常数值以获得更好的可读性,但这可能是矫枉过正。

于 2013-02-22T19:56:46.720 回答
1

你在寻找类似的东西value1.intValue() == value2.intValue()吗?或者你可以只输入 cast 。

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

同一根拐杖反其道而行之。

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

唯一的方法是非常低效的 byte[] 到 String 的转换。

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

改用 (Hash-)Map 会使它再次变得更快。

但我认为你不会对这个解决方案感到满意。

于 2013-02-22T19:49:08.060 回答
1

鉴于这似乎是数据包中的版本字符串或其他东西,那么值的数量是有限的并且是合理的数量。所以它们可以封装在一个枚举中。枚举可以封装高效的代码,用于将输入数据中的四个字节转换为代表枚举。(我执行该转换的代码不一定是最有效的。也许,给定少量版本,一个很好的内部数组或整数到枚举的映射会起作用。)

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 回答