Оголошення неподписаного int в Java


316

Чи є спосіб оголосити неподписаний int на Java?

Або питання також може бути сформульовано так: Що таке еквівалент Java без підпису?

Лише кажу вам, в якому контексті я дивився на реалізацію Java String.hashcode(). Я хотів перевірити можливість зіткнення, якщо ціле число було 32 без знака int.


7
У Java немає непідписаних типів.
Андрій Логвінов

1
Це повідомлення може допомогти вам stackoverflow.com/a/4449161/778687
ТУСАР

2
Це, здається, не є АФАКТИЧНИМ. Пов’язано: stackoverflow.com/questions/430346/…
Джеймс Меннінг

11
Це залежить від мети, яку ви намагаєтеся досягти. Для більшості цілей усі цілі числа на Java підписані. Однак ви можете розглянути підписане ціле число як неподписане в одному конкретному випадку: ви можете зрушити праворуч без розширення знака, використовуючи >>>оператор замість >>.
dasblinkenlight

Відповіді:


310

У Java немає типу даних для непідписаних цілих чисел .

Ви можете визначити longзамість anintЯкщо потрібно зберігати великі значення, символу.

Ви також можете використовувати підписане ціле число, як якщо б воно не було підписане. Перевага представлення комплементу двох полягає в тому, що більшість операцій (таких як додавання, віднімання, множення та зсув лівої сторони) є ідентичними на двійковому рівні для підписаних і непідписаних цілих чисел. Однак декілька операцій (поділ, зсув правиці, порівняння та кастинг) відрізняються. Як і в Java SE 8, нові методи в Integerкласі дозволяють повністю використовувати intтип даних для виконання непідписаної арифметики :

У Java SE 8 і пізніших версіях ви можете використовувати тип даних int для представлення непідписаного 32-бітного цілого числа, яке має мінімальне значення 0 і максимальне значення 2 ^ 32-1. Використовуйте клас Integer, щоб використовувати тип даних int як ціле число без підпису. Статичні методи, такі як compareUnsigned,divideUnsigned і т.д. , які були додані до класу Integer для підтримки арифметичних операцій для цілих чисел без знака.

Зауважте, що intзмінні все ще підписуються при оголошенні, але непідписана арифметика тепер можлива за допомогою цих методів у Integerкласі.


11
Якщо чесно, для багатьох проектів технічні вимоги не такі суворі, і ви дійсно можете дозволити собі «витрачати» пам’ять так.
Симеон Віссер

6
Я знаю, я також розумію початкове призначення Java. Але, наприклад, смартфони не мають зайвої пам'яті. І зазвичай вони використовують Java, наскільки я знаю. Але добре, я не хочу розпочинати війну між програмістами Java та іншими.
Томаш Зато - Відновити Моніку

122
Для мене це не лише випадання грошей. Коли ви працюєте на трохи рівні, з безпідпискою працювати просто простіше
Cruncher

24
Що стосується Java 8, це вже не відповідає дійсності . У Java SE 8 та новіших версіях ви можете використовувати intтип даних для представлення непідписаного 32-бітного цілого числа, яке має мінімальне значення 0та максимальне значення 2^32-1. - див. docs.oracle.com/javase/tutorial/java/nutsandbolts/… та docs.oracle.com/javase/8/docs/api/java/lang/Integer.html
8bitjunkie

2
@ 7SpecialGems: я оновив відповідь, щоб включити цю інформацію. Незважаючи на те, що неможливо оголосити непідписані цілі числа чи виключити негативні значення, можна використовувати лише так, intяк якщо б вони не були підписані за допомогою різних методів.
Симеон Віссер

70

1
@stas У мене виникають труднощі в розумінні використання та великій справі щодо можливості використання непідписаних типів даних. З різних джерел в Інтернеті, з яких я читаю, здається, що він обертається навколо просто розширення максимального значення, а неявна за своєю природою гарантія того, що це позитивне число. Чи правильно я розумію, чи є інші основні причини? Крім того, тепер, коли Integerклас в Java 8 дозволяє використовувати непідписаний int, це різниця між простором і швидкістю (оскільки в C / C ++ вони примітивні, а в Java - це ціла обгортка об'єктів)
Абдул,

2
@Abdul - коли ви працюєте на рівні бітів (як правило, тому, що ви взаємодієте з апаратними засобами), вам потрібно значення, щоб поводитися певним чином. тобто - перекидання після 11111111 до 00000000 і т. д. Використання підписаних замість непідписаних може порушити обчислення CRC і т.д.
Lorne K

3
@Lorne K: на Java перекиньте int, навіть якщо вони підписані. Це C / C ++, де непідписаний перекидається, але підписане спричиняє "Невизначене поведінку" при переповненні. Якщо "перекидання" - це ваша єдина проблема, вам не потрібно підписувати. Я здогадуюсь, тому CRC підпрограми тощо працюють у Java без додаткових зусиль. І тому новий API додає лише розбір, форматування, порівняння, поділ та залишок. Усі інші операції, а саме всі маніпуляції з бітами, а також додавання, віднімання, множення тощо, так чи інакше роблять правильно.
Холгер

4
@Ciprian Tomoiaga: для додавання за допомогою перекидання бітові шаблони введення та результату не залежать від того, ви інтерпретуєте його як підписаний номер чи непідписаний номер. Якщо у вас є терпіння, ви можете спробувати його з усіма 2⁶⁵ комбінаціями…
Holger

3
@Holger дякую за пояснення! Справді, виявляється, тому ми фактично використовуємо доповнення 2. Я спробував це з деякими 2 ^ 8 комбінаціями ^^
Ciprian Tomoiagă

66

Будь-яке значення в int підписане чи непідписане, залежить від того, як інтерпретуються біти - Java інтерпретує біти як підписане значення (у ньому немає неподписаних примітивів).

Якщо у вас є int, який ви хочете інтерпретувати як непідписане значення (наприклад, ви читаєте int з DataInputStream, який, на вашу думку, містить неподписане значення), ви можете зробити наступний трюк.

int fourBytesIJustRead = someObject.getInt();
long unsignedValue = fourBytesIJustRead & 0xffffffffl;

Зауважте, що важливо, щоб шістнадцятковий буквал був довгим літералом, а не int літералом - отже, "l" в кінці.


3
Для мене це найкраща відповідь ... Мої дані надходять із UID картки NFC, яка може мати 4 або 8 байт ... У разі 4-х байт мені потрібно було передати її до непідписаного int, і я не зміг використовуйте ByteBuffer.getLong, оскільки це не 64-бітні дані. Дякую.
Луденв'є

Чому це потрібно довго. Ви не можете просто зробити 0xFFFFFFі зберегти Int?
Displee

19

Нам потрібні непідписані номера моделі MySQL, без знака TINYINT, SMALLINT, INT, BIGINTв jOOQ , тому ми створили jOOU , минималистичную бібліотеку підношення обгортки типів для беззнакових цілих чисел в 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. Сподіваюсь, це допомагає.

(Відмова: Я працюю в компанії, що стоїть за цими бібліотеками)


Це звучить дуже зручно! Дякуємо за згадування. :)
Лукас Суса

7

Для непідписаних номерів ви можете використовувати ці класи з бібліотеки Guava :

Вони підтримують різні операції:

  • плюс
  • мінус
  • разів
  • мод
  • ділиться на

На сьогоднішній день, здається, бракує операторів зміни байтів. Якщо вам потрібні такі, ви можете використовувати BigInteger від Java.



2

Можливо, саме це ви мали на увазі?

long getUnsigned(int signed) {
    return signed >= 0 ? signed : 2 * (long) Integer.MAX_VALUE + 2 + signed;
}
  • getUnsigned(0) → 0
  • getUnsigned(1) → 1
  • getUnsigned(Integer.MAX_VALUE) → 2147483647
  • getUnsigned(Integer.MIN_VALUE) → 2147483648
  • getUnsigned(Integer.MIN_VALUE + 1) → 2147483649

Ви приносите жертву мільйонну частку секунди часу для того, щоб ліниво набирати текст із потрійними операторами, а не якщо if. Не добре. (жартує)
ytpillai

5
Ви справді думаєте, що 2 * (long) Integer.MAX_VALUE + 2це легше зрозуміти, ніж 0x1_0000_0000L? У зв'язку з цим, чому не просто return signed & 0xFFFF_FFFFL;?
Хольгер

2

Здається, ви можете впоратися з проблемою підписання, зробивши "логічне І" на значеннях перед їх використанням:

Приклад (значення byte[] header[0]становить 0x86):

System.out.println("Integer "+(int)header[0]+" = "+((int)header[0]&0xff));

Результат:

Integer -122 = 134

2

Тут є хороші відповіді, але я не бачу жодних демонстрацій бітових операцій. Як каже Visser (зараз прийнята відповідь), Java підписує цілі числа за замовчуванням (Java 8 має цілі числа без підпису, але я ніколи їх не використовував). Без зайвих прихильників, зробимо це ...

Приклад RFC 868

Що станеться, якщо вам потрібно записати не підписане ціле число в IO? Практичний приклад - коли потрібно вивести час відповідно до RFC 868 . Для цього потрібно 32-розрядне ціле число без великого ендіану, яке кодує кількість секунд з 00:00 1 січня 1900 р. Як би ви це кодували?

Зробіть власне 32-розрядне ціле число без підпису таким чином:

Оголосити масив байтів у 4 байти (32 біта)

Byte my32BitUnsignedInteger[] = new Byte[4] // represents the time (s)

Це ініціалізує масив, див. Чи байтовані масиви байтів ініціалізовані до нуля в Java? . Тепер вам потрібно заповнити кожен байт масиву інформацією в порядку великого ендіану (або малоекземлянина, якщо ви хочете зруйнувати хаос). Якщо припустити, що у вас тривалий час, що містить час (довгі цілі числа в Яві мають 64 біти), який називається secondsSince1900(який використовує лише перші 32 біти, і ви обробили той факт, що посилання на дату 00:00 1 січня 1970 р.), То ви можете використовувати логічний AND, щоб витягти з нього біти і перемістити ці біти в позиції (цифри), які не будуть ігноровані, коли будете переведені в байт, і в порядку великого ендіану.

my32BitUnsignedInteger[0] = (byte) ((secondsSince1900 & 0x00000000FF000000L) >> 24); // first byte of array contains highest significant bits, then shift these extracted FF bits to first two positions in preparation for coersion to Byte (which only adopts the first 8 bits)
my32BitUnsignedInteger[1] = (byte) ((secondsSince1900 & 0x0000000000FF0000L) >> 16);
my32BitUnsignedInteger[2] = (byte) ((secondsSince1900 & 0x000000000000FF00L) >> 8);
my32BitUnsignedInteger[3] = (byte) ((secondsSince1900 & 0x00000000000000FFL); // no shift needed

Наше my32BitUnsignedIntegerтепер еквівалентне непідписаному 32-бітовому цілому цілому цілому числу, яке відповідає стандарту RCF 868. Так, довгий тип даних підписаний, але ми проігнорували цей факт, оскільки ми припустили, що секунди Since1900 використовували лише нижні 32 біти). Через примушування довгих байтів, всі біти вище 2 ^ 7 (перші дві цифри в шістнадцятковій версії) будуть ігноруватися.

Посилання на джерело: Мережеве програмування Java, 4-е видання.


1

Щойно зробив цей фрагмент коду, який перетворює "this.altura" з негативного в додатне число. Сподіваюся, що це допомагає комусь, хто потребує

       if(this.altura < 0){    

                        String aux = Integer.toString(this.altura);
                        char aux2[] = aux.toCharArray();
                        aux = "";
                        for(int con = 1; con < aux2.length; con++){
                            aux += aux2[con];
                        }
                        this.altura = Integer.parseInt(aux);
                        System.out.println("New Value: " + this.altura);
                    }

-19

Ви можете використовувати функцію Math.abs (число). Він повертає додатне число.


12
nitpick: ні, якщо ви заїдетеMIN_VALUE
Dennis Meng

2
@ kyo722 Я не уявляю, що це поверне позитивне значення у діапазоні неподписаних примітивів.
Флоріан Р. Кляйн

1
nitpick №2: не, якщо ви перейдете до0
genisage
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.