Вопрос

Есть ли в Java способ использовать числа без знака, как в (Моем) SQL?

Например:Я хочу использовать 8-битную переменную (byte) с диапазоном , подобным: 0 ... 256;вместо того, чтобы -128 ... 127.

Это было полезно?

Решение

Нет, в Java нет никаких беззнаковых примитивных типов, кроме char (который фактически имеет значения 0-65535).Это боль (особенно для byte), но это так.

Обычно вы либо придерживаетесь одного и того же размера и переполняете отрицательные числа для «высоких» чисел, либо используете более широкий тип (например, short для byte) и справиться с дополнительными требованиями к памяти.

Другие советы

Вы можете использовать класс для имитации беззнакового числа.Например

public class UInt8 implements Comparable<UInt8>,Serializable
   {
   public static final short MAX_VALUE=255;
   public static final short MIN_VALUE=0;
   private short storage;//internal storage in a int 16

   public UInt8(short value)
      {
      if(value<MIN_VALUE || value>MAX_VALUE) throw new IllegalArgumentException();
      this.storage=value;
      }

   public byte toByte()
      {
      //play with the shift operator ! << 
      }
  //etc...
   }

В основном вы можете использовать числа со знаком, как если бы они были беззнаковыми.Большинство операций остаются прежними, некоторые необходимо изменить.Видеть эта почта.

Внутренне вам не следует использовать меньшие значения — просто используйте int.Насколько я понимаю, использование меньших единиц только замедляет процесс.Это не экономит память, поскольку внутренне Java использует размер слова системы для всей памяти (она не упаковывает слова).

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

Вы когда-нибудь замечали, что char (любая операция) char возвращает int?Они просто не ожидают, что вы будете использовать другие типы.

Исключением являются массивы (которые, как я полагаю, будут упакованы) и операции ввода-вывода, где использование меньшего типа может оказаться полезным...но маскирование тоже будет работать.

Нет, ты не можешь это изменить.Если вам нужно что-то большее, чем 127, выберите что-то большее, чем байт.

Если вам нужно оптимизировать ваше хранилище (например,большая матрица) вы можете закодировать большие положительные числа отрицательными числами, чтобы сэкономить место.Затем вы должны изменить числовое значение, чтобы при необходимости получить фактическое значение.Например, я хочу манипулировать только короткими положительными числами.Вот как это возможно в Java:

        short n = 32767;
        n = (short) (n + 10);
        System.out.println(n);     
        int m = (int) (n>=0?n:n+65536); 
        System.out.println(m);

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

Я совсем новичок в Java и программировании.Тем не менее, недавно я столкнулся с такой же ситуацией, когда потребовались значения без знака.

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

Общая идея состоит в том, чтобы создать интерфейс, я назвал его: UnsignedNumber<Base, Shifted> и расширять Number.class при реализации абстрактного AbstractUnsigned<Base, Shifted, Impl extends AbstractUnsigned<Base, Shifted, Impl>> класс.

Итак, базовый параметризованный тип представляет базовый тип, Сдвинутый представляет фактический тип Java.Impl - это ярлык для реализации этого абстрактного класса.

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

Наконец, потребовалось еще пару дней, чтобы закодировать фабрики и подклассы реализации.

До сих пор я знал:UByte и MUByte UShort и MUShort UInt и MUInt ...И т.д.

Они являются потомками AbstractUnsigned:Расширение UByte или MUByte AbstractUnsigned<Byte, Short, UByte> или AbstractUnsigned<Byte, Short, MUByte> Ушорт или мушорт удлиненный AbstractUnsigned<Short, Integer, UShort> или AbstractUnsigned<Short, Integer, MUShort> ...и т.д.

Общая идея состоит в том, чтобы принять unsigned upper limit за сдвинутый (приведенный) тип и кодировать перенос отрицательных значений, поскольку они должны были исходить не из нуля, а из unsigned upper limit.

Обновить:(Благодаря Аджеанцы добрые и вежливые указания)

/**
* Adds value to the current number and returns either
* new or this {@linkplain UnsignedNumber} instance based on
* {@linkplain #isImmutable()}
*
* @param value value to add to the current value
* @return new or same instance
* @see #isImmutable()
*/
public Impl plus(N value) {
    return updater(number.plus(convert(value)));
}

Это доступный извне метод AbstractUnsigned<N, Shifted, Impl> (или как это было сказано ранее AbstractUnsigned<Base, Shifted, Impl>);Теперь перейдем к работе под капотом:

private Impl updater(Shifted invalidated){
    if(mutable){
        number.setShifted(invalidated);
        return caster.apply(this);
    } else {
        return shiftedConstructor.apply(invalidated);
    }
}

В приведенном выше частном методе mutable является private final boolean из одного AbstractUnsigned. number является одним из внутренних частных классов, который заботится о преобразовании Base Для Shifted и наоборот.Что имеет значение в соответствии с предыдущими 'часть о том, что я делал прошлым летом' это два внутренних объекта: caster и shiftedConstructor:

final private Function<UnsignedNumber<N, Shifted>, Impl> caster;
final private Function<Shifted, Impl> shiftedConstructor;

Это параметризованные функции для приведения N (или Base) к Shifted или создать новый Impl экземпляр, если текущий экземпляр реализации AbstractUnsigned<> является неизменяемым.

Shifted plus(Shifted value){
    return spawnBelowZero.apply(summing.apply(shifted, value));
}

В этом фрагменте показан метод добавления number объект.Идея состояла в том, чтобы всегда использовать Shifted внутренне, потому что неизвестно, когда будут созданы положительные ограничения "исходного" типа. shifted является внутренним параметризованным полем, которое несет значение целого AbstractUnsigned<>.Двое других Function<> производные объекты приведены ниже:

final private BinaryOperator<Shifted> summing;
final private UnaryOperator<Shifted> spawnBelowZero;

Первый выполняет сложение двух Shifted ценности.И последний выполняет нерестовую транспозицию ниже нуля.

А теперь пример из одного из заводских шаблонов "ад" для AbstractUnsigned<Byte, Short> специально для упомянутых ранее spawnBelowZero UnaryOperator<Shifted>:

...,
         v-> v >= 0
         ? v
         : (short) (Math.abs(Byte.MIN_VALUE) + Byte.MAX_VALUE + 2 + v),
...

если Shifted v положительно, на самом деле ничего не происходит, и возвращается исходное значение.В противном случае:необходимо рассчитать верхний предел Base тип, который является Byte и прибавьте к этому отрицательное значение v.Если, допустим,, v == -8 тогда Math.abs(Byte.MIN_VALUE) произведет 128 и Byte.MAX_VALUE произведет 127 что дает 255 + 1, чтобы получить исходный верхний предел, который был уменьшен на знаковый бит, как я понял, и так желаемый 256 находится на своем месте.Но самое первое отрицательное значение является на самом деле это 256 вот почему +1 снова или +2 в общей сложности.Наконец-то, 255 + 2 + v который является -8 дает 255 + 2 + (-8) и 249

Или в более наглядном виде:

0 1 2 3 ... 245 246 247 248 249 250 251 252 253 254 255 256
                             -8  -7  -6  -5  -4  -3  -2  -1

И завершить все это:это определенно не облегчает вашу работу и не экономит байты памяти, но у вас есть довольно желательное поведение, когда это необходимо.И вы можете использовать это поведение практически с любым другим Number.class подклассы. AbstractUnsigned являясь подклассом Number.class сам по себе предоставляет все удобные методы и константы аналогично другим "родным" Number.class подклассы, включая MIN_VALUE и MAX_VALUE и многое другое, например, я закодировал удобный метод для изменяемых подклассов, вызываемых makeDivisibileBy(Number n) который выполняет простейшую операцию value - (value % n).

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top