Сравните int с символьной константой в Java

у меня есть двоичный файл, который использует наборы из 4 символов в виде чисел, которые имеют "смысл". Например, 4 байта '0005', что равно 808464437 в целочисленной форме.

Я бы предпочел представить их в моем коде 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 байта и поместить их в какой-то тип данных. Моя проблема сравнение некоторого типа данных с массивом const char '0005'.

как сравнить int или любую другую форму с массивом символов const, например '0005' в Java? мне нужно сделать это как можно более эффективно!

7 ответов


наиболее эффективным способом было бы работать с целыми числами - что-то вроде final int V0005 = 0x30303035 (комбинация нескольких разных идей, рассмотренных здесь) было бы управляемым. Java просто не имеет таких целочисленных литералов, которые вы ищете.

Если вы действительно хотите работать со строками, вам нужно сначала прочитать символы в массиве байтов, а затем преобразовать их в строку (кодировка по умолчанию обычно работает как надмножество ASCII). Однако, было бы меньше эффективный.

вы можете написать функцию для вычисления постоянных значений из простых чисел (например, 5) для лучшей читаемости, но это, вероятно, излишне.


Спасибо за объяснение вашего ответа.

вот как преобразовать из 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) является эффективным.


массив символов в java-это не что иное, как String в java. Вы можете использовать строку в переключателях в Java7, но я не знаю эффективности сравнений.

поскольку только последний элемент вашего массива символов, похоже, имеет значение, вы можете сделать с ним случай переключения. Что-то вроде

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


получив немного от некоторых других ответов (@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 С правильным именем и это будет сделано автоматически.


вы ищете что-то вроде value1.intValue() == value2.intValue()? Или вы можете просто набрать cast.

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

та же трость идет в другую сторону.

int myInt = 6;
char myChar = (char) myInt;

единственным способом было бы очень неэффективное преобразование байта[] в строку.

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

использование (хэш-)карты вместо этого сделает его быстрее.

но я думаю, вы не будете удовлетворены этим решением.


учитывая, что это, по-видимому, строка версии в пакете или что-то еще, то количество значений конечное и разумное. Таким образом, они могут быть инкапсулированы в перечисление. Перечисление может инкапсулировать эффективный код для преобразования из четырех байтов во входных данных в Представительное перечисление. (Мой код для выполнения этого преобразования не обязательно является самым эффективным. Возможно, учитывая небольшое количество версий, хороший внутренний массив или отображение ints в перечисления работа.)

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