Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 30
×

Фиксированный размер полей в Java классе

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

Хочу создать объект в Java, что-бы суммарный максимальный размер всех его полей был всегда фиксирован независимо от платформы и jvm. Что бы сам объект представлял собой некий протокол (или спецификацию), смотря на которые сразу было понятно сколько байт займут его поля. Например поле field 1 должно быть 4 байта, а поле field2 должно быть 8 байт и тд тп..

Например

class Chunk {
    private int field1;
    private long field2;
    private byte[] bytes = new byte[2];
    private long timestamp;
}

Я понимаю, что типы данных в java имеют фиксиорованный размер, но чтение класса, заставит разработчика думать о то том сколько какой тип занимает данных и тд тп. Хочу сделать объект в таком виде:

class Chunk {
    private byte[] field1 = new byte[4];
    private byte[] field2 = new byte[8];
    private byte[] bytes = new byte[2];
    ...
}

тогда всем будет все понятно. Это нормальная идея или это только запутает людей?
Спасибо

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Для сериализации-десериализации есть специализированные вещи типа protocol buffers/thrift/cap’n’proto а для валидации можно сделать фреймворк и развесить аннотации или использовать другой способ описания меданных и гарантировать ошибку которая не пропусти неправильное использование.

Это не лучшая идея, поскольку очень сложна для понимания.
Рекомендация: если это пользовательский ввод, организовывай описание полей и контроль вводимых данных. Если это что-то другое, то не заморачивайся, добавляй в документацию лимиты, и швыряй исключения. Это важно, чтобы когда наступил на грабли — падало именно твоё исключение, а не хер пойми что от системы.

Почему так: если данные лимитированы, то этому есть объективная причина. Значит данные физически не могут (не должны) привышать этот лимит. Ты же не заморачиваешься лимитацией целочисленных типов? Потому что это и ежу понятно. Вот и с другими данными тому же ежу будет понятно из документации.

Акцент: такие моменты, с выдачей исключений и тщательным приведением типов, годятся для проектов со средней нагрузкой. В случае highload ты можешь попросту засрать систему исключениями, не говоря уже о тормозах преобразований. Там вероятно придётся разделять функцию контроля в отдельную задачу, чтобы на ввод в систему преобразования и хранения поступали уже доверенные данные и работали безо всяких проверок.

Так что пиши String и убей в себе перфекциониста, тебе за это не доплатят, поверь.

я хочу серализовать поля этого класса в последовательность байт и потом обратно сериализовать в объект, но при этом хочу, что бы был минимальный размер сохраненных данных — только последовательность байт в бинарном файле. Плюс максимальная простота для понимания и контроль над происходящим. Сторониие фреймворки добавляют сложности.

Якщо поля обмежуються примітивними типами, то розмір об’єкту в байтах і так буде фіксований.
Чому це повинно «заставить разработчика думать о то том сколько какой тип занимает данных», незрозуміло — класи, що реалізують «новий велосипед» з сереалізації/десереалізації він же писати не буде, а буде використовувати ті, які ти напишеш.

я буду сериализовать не весь объект, а только его поля. Как такового велосипеда не надо. Нужно просто взять поля и сохранить их как последовательность байт в файл. И когда я буду читать и восстанавливать объект — я буду знать, что первые 4 байт — это поле 1, вторые 8 байт — это поле 2.

я буду сериализовать не весь объект, а только его поля.
И когда я буду читать и восстанавливать объект — я буду знать, что первые 4 байт — это поле 1, вторые 8 байт — это поле 2.

И что вам мешает делать то же самое с нормальным джавовым объектом?

Посмотрите на использование protobuf

я хочу серализовать поля этого класса в последовательность байт и потом обратно сериализовать в объект

1) То что вы описали для такой задачи не подойдет. Объекты в джава НЕ есть структуры данных.
2) Джавовая сериализация не зависит от того как в памяти распологаются поля
3) Если хочется повыпендриватся, то попробуте посмотреть на docs.oracle.com/...​/java/nio/ByteBuffer.html

В рамках одной архитектуры процессора скорее всего будет работать, при переносе между архитектурами, надо читать спеки.

А что если сделать примерно вот так:

package test;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

public class Chunk {
    private static int MY_EXPECTED_PREDICTABLE_DESCRIBED_IN_DOCS_IMMUTABLE_TOTAL_FIELDS_SIZE_IN_BYTES = 14;

    private byte[] field1 = new byte[4];
    private byte[] field2 = new byte[8];
    private byte[] field3 = new byte[2];


    public void serialize() throws IOException {
        byte[] chunkData = new byte[MY_EXPECTED_PREDICTABLE_DESCRIBED_IN_DOCS_IMMUTABLE_TOTAL_FIELDS_SIZE_IN_BYTES];

        System.arraycopy(field1,0, chunkData, 0, field1.length);
        System.arraycopy(field2,0, chunkData, 4, field2.length);
        System.arraycopy(field3,0, chunkData, 12, field3.length);
        FileUtils.writeByteArrayToFile(new File("pathname"), chunkData);
    }

    public Chunk deserialize() throws IOException {
        Chunk chunk = new Chunk();

        byte[] absolutelyPredictableByteArrayOfSize14 = Files.readAllBytes(new File("pathname").toPath());

        System.arraycopy(absolutelyPredictableByteArrayOfSize14,0, chunk.field1, 0, field1.length);
        System.arraycopy(absolutelyPredictableByteArrayOfSize14,4, chunk.field2, 0, field2.length);
        System.arraycopy(absolutelyPredictableByteArrayOfSize14,12, chunk.field3, 0, field3.length);

        return chunk;
    }
}

Тогда мы не зависим ни от архитектуры, ни от сериализаторов. Это абсолютно прозрачно. Как по мне

А что если сделать примерно вот так

Зачем вам несколько массивов если можно использовать 1 и методы которые умеют читать куски массива соответствующие полям? (Так люди решают проблемы с аллокацией памяти и загрузкой структур в кеши процессоров)

Тогда мы не зависим ни от архитектуры, ни от сериализаторов. Это абсолютно прозрачно

При сериализации/десериализации прозрачно (если не лажануть с индексами :) ).
При работе с объектами что? Для field2 мне нужен лонг, а не 4 байта. Подобный код будет очень проблематично поддерживать.
Если вы уж пишете свой сериализатор, то просто сделайте потоковые чтение и запись с/в нормальных джава-объектов. Но лучше посмотрите на готовые и __отлаженые__ решения.

Подобный код будет очень проблематично поддерживать.

да именно об этом я и спрашиваю. Тогда действительно лучше хранить в нормальных типах

Это лишнее. Лучше сделай архивирование, и будет тебе счастье. Современные процы это делают ооочень шустренько. Или наоборот — наплюй на лимиты по размерам, память всякая сейчас тоже недорога, полгига туда-сюда роли не сыграют.

Используя джаву, помни: jvm всегда лучше распорядится памятью, чем ты.

помощь заключается в том чтобы считать размер нефиксированным и проблема пропала из-за того что больше не применима?)

а який може бути фіксований розмір об’єкту «независимо от платформы и jvm», коли object pointers можуть бути як uncompressed, так і compressed ? :)

я вообще не знаю для чего такое понадобилось

указатели не нужно сохранять, только данные (field1, field2, bytes)

Мой совет — просто сделай 2 структуры: честную жабу, и просто массив байт. Соответственно, реализуй интерфейсы сереализации, и будет тебе счастье. Вся жаба так работает, ИЧСХ, никаких проблем не испытывает.

Виртуальная машина, сборщик мусора — "

заставит разработчика думать о то том сколько какой тип занимает данных

"

field1, field2 .. — це ж поінтери на масиви, в залежності від архітектури різний розмір. int, long — завжди одного й того ж розміру (docs.oracle.com/...​tsandbolts/datatypes.html)

поинтеры не нужно сохранять — только данные

Підписатись на коментарі