Как использовать целое число без знака в Java 8 и Java 9?

82

На странице Oracle «Примитивные типы данных» упоминается, что в Java 8 добавлена ​​поддержка беззнаковых целых и длинных чисел:

int: По умолчанию intтип данных представляет собой 32-битное целое число со знаком в дополнительном коде, минимальное значение которого равно −2 31, а максимальное - 2 31 −1. В Java SE 8 и более поздних версиях вы можете использовать intтип данных для представления беззнакового 32-битного целого числа, которое имеет минимальное значение 0 и максимальное значение 2 32 -1. Используйте Integerкласс, чтобы использовать intтип данных как целое число без знака. См. Раздел «Числовые классы» для получения дополнительной информации. В класс были добавлены статические методы, такие как compareUnsignedи divideUnsignedт.д., Integerдля поддержки арифметических операций с целыми числами без знака.

long: Тип longданных - 64-битное целое число с дополнением до двух. Знак longимеет минимальное значение -2 63 и максимальное значение 2 63 -1. В Java SE 8 и более поздних версиях вы можете использовать longтип данных для представления беззнакового 64-битного массива long, который имеет минимальное значение 0 и максимальное значение 2 64 -1. Используйте этот тип данных, когда вам нужен более широкий диапазон значений, чем тот, который предоставляется int. LongКласс также содержит методы , такие как compareUnsigned, и divideUnsignedт.д. , чтобы поддерживать арифметические операции для беззнакового long.

Однако я не могу объявить беззнаковое длинное или целое число. Следующий код, например, выдает сообщение об ошибке компилятора «литерал вне допустимого диапазона» (я, конечно, использую Java 8), когда он должен быть в диапазоне (присвоенное значение равно 2 64 -1). :

public class Foo {
    static long values = 18446744073709551615L;
    
    public static void main(String[] args){
        System.out.println(values);
    }  
}

Итак, есть ли способ объявить unsigned int или long?

Пабсе
источник
2
Что возвращается в вашей константе Long.MAX_VALUE в java 8?
Бруно Франко
21
Не существует целого числа без знака или длинного типа без знака. Если вы используете один из новых методов, этот метод будет обрабатывать 32-битное или 64-битное целое число, как если бы оно было беззнаковым. Но это все. Тип переменной по-прежнему будет подписан, и вам нужно помнить, что вы используете его как беззнаковое число. Они не добавляли беззнаковые литералы, но, возможно, они добавят их в Java 9, если их найдет достаточное количество людей. :)
ajb
5
На самом деле они ничего не изменили, кроме добавления новых методов.
Hot Licks
4
Насколько я могу судить, все, что они сделали, это добавили методы, которые могут возвращать значения без знака, но не позволяют объявлять значения без знака. Какая-то глупость, если вы спросите меня, и настоящая боль. Интересно, можно ли было бы использовать Integer.divideUnsigned с одним параметром, равным 1, а другим - любым числом, которое вы хотите рассматривать как беззнаковое. Насколько я могу судить, будет работать, но, похоже, это действительно глупый способ делать что-то.
cluemein
@ajb, как я могу оказать какую-либо помощь в процессе "устранения ошибок", чтобы наконец увидеть правильную неподписанную версию Java? :)
Matthieu

Ответы:

51

Согласно опубликованной вами документации и этому сообщению в блоге - нет никакой разницы при объявлении примитива между неподписанным int / long и подписанным. «Новая поддержка» - это добавление статических методов в классы Integer и Long, например Integer.divideUnsigned. . Если вы не используете эти методы, ваша длинная длина «без знака» выше 2 ^ 63-1 будет просто старой длинной с отрицательным значением.

На первый взгляд не похоже, что есть способ объявить целочисленные константы в диапазоне за пределами +/- 2 ^ 31-1 или +/- 2 ^ 63-1 для длинных. Вам придется вручную вычислить отрицательное значение, соответствующее положительному значению за пределами допустимого диапазона.

Sbodd
источник
87

Ну, даже в Java 8, longи intони все еще подписаны, только некоторые методы обрабатывают их как беззнаковые . Если вы хотите написать longтакой беззнаковый литерал, вы можете сделать

static long values = Long.parseUnsignedLong("18446744073709551615");

public static void main(String[] args) {
    System.out.println(values); // -1
    System.out.println(Long.toUnsignedString(values)); // 18446744073709551615
}
Kajacx
источник
5
Наблюдение, которое я вижу в этом, заключается в том, что порядок поврежден. Если бы я получил беззнаковое длинное число от какой-либо системы (Twitter, кстати, предоставляет такие идентификаторы) и хотел бы отсортировать их, возможно, потому, что я знал, что они хронологические, тогда все, кроме Long.MAX_VALUE, фактически будет отображаться перед 0 как отрицательное с реализацией Java :-(. Вместо этого, похоже, нужно также сдвинуть его вниз так, чтобы беззнаковый 0 соответствовал подписанному Long.MIN_VALUE.
Дэвид Смайли
10
@DavidSmiley Хорошее замечание. Чтобы отсортировать беззнаковые длинные строки , используйте Long.compareUnsigned или передайте этот метод в качестве компаратора для функций сортировки,
kajacx
26
    // Java 8
    int vInt = Integer.parseUnsignedInt("4294967295");
    System.out.println(vInt); // -1
    String sInt = Integer.toUnsignedString(vInt);
    System.out.println(sInt); // 4294967295

    long vLong = Long.parseUnsignedLong("18446744073709551615");
    System.out.println(vLong); // -1
    String sLong = Long.toUnsignedString(vLong);
    System.out.println(sLong); // 18446744073709551615

    // Guava 18.0
    int vIntGu = UnsignedInts.parseUnsignedInt(UnsignedInteger.MAX_VALUE.toString());
    System.out.println(vIntGu); // -1
    String sIntGu = UnsignedInts.toString(vIntGu);
    System.out.println(sIntGu); // 4294967295

    long vLongGu = UnsignedLongs.parseUnsignedLong("18446744073709551615");
    System.out.println(vLongGu); // -1
    String sLongGu = UnsignedLongs.toString(vLongGu);
    System.out.println(sLongGu); // 18446744073709551615

    /**
     Integer - Max range
     Signed: From −2,147,483,648 to 2,147,483,647, from −(2^31) to 2^31 – 1
     Unsigned: From 0 to 4,294,967,295 which equals 2^32 − 1

     Long - Max range
     Signed: From −9,223,372,036,854,775,808 to 9,223,372,036,854,775,807, from −(2^63) to 2^63 − 1
     Unsigned: From 0 to 18,446,744,073,709,551,615 which equals 2^64 – 1
     */
черника0xff
источник
10
Следует добавить некоторые пояснения, а не просто выбросить код.
cluemein
22

Там нет никакого способа , как объявить беззнаковое длинное или Int в Java 8 или Java 9. Но некоторые методы лечения их , как если бы они были без знака, например:

static long values = Long.parseUnsignedLong("123456789012345678");

но это не объявление переменной.

1ac0
источник
3
Я понимаю, почему бы и нет. они могли бы легко добавить типы uint и ulong
EKanadily 02
@docesam в этом и этом документе есть подробное объяснение. Короче говоря, в класс Integer добавлены только методы беззнаковой обработки. и если бы они могли легко добавить, я не знаю, почему они этого не сделают ;-)
1ac0 03
@ Ladislav DANKO есть расчетливые люди, есть другие ребята. Я не уверен, было ли это - в данном случае - благоразумным или нет, но мне кажется, что оракул не столь благоразумен.
EKanadily 04
1
@docesam Нет, у них не могло быть "легко добавляемых типов uint и ulong". Это потребует капитального ремонта JLS, спецификации JVM, JNI, множества библиотек (например, java.util.Arrays), отражения и многого другого.
Наюки
1
@ Michaelangel007 Привет, я думаю, мы подходим к этой теме с другими предпосылками. Напишите мне письмо, и мы поговорим о деталях?
Наюки
4

Если возможно использование сторонней библиотеки, существует jOOU (дополнительная библиотека от jOOQ ), которая предлагает типы оболочки для целых чисел без знака в Java. Это не совсем то же самое, что поддержка примитивного типа (и, следовательно, байтового кода) для беззнаковых типов, но, возможно, этого достаточно для вашего варианта использования.

import static org.joou.Unsigned.*;

// and then...
UByte    b = ubyte(1);
UShort   s = ushort(1);
UInteger i = uint(1);
ULong    l = ulong(1);

Все эти типы расширяются java.lang.Numberи могут быть преобразованы в примитивные типы более высокого порядка иBigInteger .

(Отказ от ответственности: я работаю в компании, стоящей за этими библиотеками)

Лукас Эдер
источник