Можно ли использовать структурные конструкции в Java? - PullRequest
8 голосов
/ 31 июля 2011

Я рассматриваю возможность использования Java для большого проекта, но мне не удалось найти ничего, что удаленно представляло бы структуры в Java.Мне нужно иметь возможность преобразовывать сетевые пакеты в структуры / классы, которые можно использовать в приложении.

Я знаю, что можно использовать RandomAccessFile, но этот способ НЕ приемлем,Поэтому мне любопытно, можно ли «привести» набор байтов к структуре, как я мог бы это сделать в C. Если это невозможно, я не могу использовать Java.

Так что вопросСпрашивается, можно ли привести выровненные данные в класс без каких-либо дополнительных усилий, кроме указания выравнивания и типов данных?

Ответы [ 8 ]

16 голосов
/ 31 июля 2011

Нет. Вы не можете привести массив байтов к объекту класса.

При этом вы можете использовать java.nio.Buffer и легко извлекать необходимые поля для объекта, подобного этому:

class Packet {

    private final int type;
    private final float data1;
    private final short data2;

    public Packet(byte[] bytes) {
        ByteBuffer bb = ByteBuffer.wrap(bytes);
        bb.order(ByteOrder.BIG_ENDIAN); // or LITTLE_ENDIAN

        type = bb.getInt();
        data1 = bb.getFloat();
        data2 = bb.getShort();
    }
}
9 голосов
/ 31 июля 2011

Вы в основном спрашиваете, можете ли вы использовать специфичное для C решение проблемы на другом языке. Ответ, как и ожидалось, «нет».

Однако вполне возможно создать класс, который принимает набор байтов в своем конструкторе и создает соответствующий экземпляр.

class Foo {

  int someField;
  String anotherField;

  public Foo(byte[] bytes) {
    someField = someFieldFromBytes(bytes);
    anotherField = anotherFieldFromBytes(bytes);
    etc.
 }
}

Вы можете убедиться, что существует однозначное сопоставление экземпляров класса с байтовыми массивами. Добавьте метод toBytes () для сериализации экземпляра в байты.

4 голосов
/ 31 июля 2011

Нет, вы не можете этого сделать.Java просто не имеет тех же понятий, что и C.

Вы можете создать класс, который будет вести себя как структура:

public class Structure {
    public int field1;
    public String field2;
}

, и у вас может быть конструктор, который принимает массив илибайты или DataInput для чтения байтов:

public class Structure {
    ...
    public Structure(byte[] data) {
        this(new DataInputStream(new ByteArrayInputStream(data)));
    }

    public Structure(DataInput in) {
        field1 = in.readInt();
        field2 = in.readUTF();
    }
}

, затем считывание байтов с провода и накачка их в Structures:

byte[] bytes = network.read();
DataInputStream stream = new DataInputStream(new ByteArrayInputStream(bytes));
Structure structure1 = new Structure(stream);
Structure structure2 = new Structure(stream);
...

Это не так кратко, как C, ноэто довольно близкоОбратите внимание, что интерфейс DataInput полностью удаляет любые искажения с порядком байтов от вашего имени, так что это определенно преимущество по сравнению с C.

2 голосов
/ 31 июля 2011

Как говорит Джошуа, сериализация - это типичный способ делать подобные вещи. Однако у вас есть другие двоичные протоколы, такие как MessagePack, ProtocolBuffers и AvRO.

Если вы хотите поиграть со структурами байт-кода, посмотрите на ASM и CGLIB; они очень распространены в приложениях Java.

1 голос
/ 31 июля 2011
ByteBuffer.wrap(new byte[] {}).getDouble();
1 голос
/ 31 июля 2011

Нет ничего, что соответствует вашему описанию.

Самым близким к структуре в Java является простой класс, который содержит значения, доступные через его поля или через методы set / get.

Типичным средством преобразования между экземплярами класса Java и представлениями на проводе является сериализация Java, которая может быть сильно настроена по мере необходимости. Это то, что используется Java Remote API Invocation API и работает очень хорошо.

0 голосов
/ 31 июля 2011

Вы не можете привести массив байтов к экземпляру класса. Но вы можете сделать намного больше с Java. У Java есть внутренний, очень сильный и очень гибкий механизм сериализации. Это то, что вам нужно. Вы можете читать и записывать объект в / из потока.

Если обе стороны написаны на языке Java, проблем нет вообще. Если одна из сторон не является Java, вы можете использовать вашу сериализацию. Начните с чтения javadoc из java.util.Serializable.

0 голосов
/ 31 июля 2011

Нет, это невозможно. Вы пытаетесь использовать Java как C, что неизбежно вызывает сложности. Либо научитесь делать вещи по-Java, либо вернитесь к C.

В этом случае способ Java, вероятно, будет включать DataInputStream и / или DataOutputStream .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...