Mendeklarasikan int unsigned di Java


316

Apakah ada cara untuk mendeklarasikan int tidak ditandatangani di Jawa?

Atau pertanyaannya dapat dibingkai seperti ini: Apa yang setara dengan Java dari unsigned?

Hanya untuk memberi tahu Anda konteks saya sedang melihat implementasi Java String.hashcode(). Saya ingin menguji kemungkinan tabrakan jika integer 32 int bertanda tangan.


7
Tidak ada tipe yang tidak ditandatangani di Jawa.
Andrew Logvinov

1
Posting ini mungkin membantu Anda stackoverflow.com/a/4449161/778687
tusar

2
Sepertinya bukan cara AFAICT. Terkait: stackoverflow.com/questions/430346/…
James Manning

11
Itu tergantung pada tujuan yang ingin Anda capai. Untuk sebagian besar tujuan, semua bilangan bulat di Jawa ditandatangani. Namun, Anda dapat memperlakukan bilangan bulat yang ditandatangani sebagai tidak ditandatangani dalam satu kasus tertentu: Anda dapat menggeser ke kanan tanpa perpanjangan tanda dengan menggunakan >>>operator sebagai gantinya >>.
dasblinkenlight

Jawaban:


310

Java tidak memiliki tipe data untuk bilangan bulat tak bertanda .

Anda bisa mendefinisikan longbukan intjika Anda perlu menyimpan nilai besar.

Anda juga dapat menggunakan bilangan bulat yang ditandatangani seolah-olah itu tidak ditandatangani. Manfaat dari representasi komplemen dua adalah bahwa sebagian besar operasi (seperti penjumlahan, pengurangan, perkalian, dan shift kiri) identik pada tingkat biner untuk bilangan bulat yang ditandatangani dan tidak ditandatangani. Namun, beberapa operasi (divisi, shift kanan, perbandingan, dan casting) berbeda. Pada Java SE 8, metode baru di Integerkelas memungkinkan Anda untuk sepenuhnya menggunakan inttipe data untuk melakukan aritmatika yang tidak ditandatangani :

Di Java SE 8 dan yang lebih baru, Anda bisa menggunakan tipe data int untuk mewakili integer 32-bit yang tidak ditandatangani, yang memiliki nilai minimum 0 dan nilai maksimum 2 ^ 32-1. Gunakan kelas Integer untuk menggunakan tipe data int sebagai integer yang tidak ditandatangani. Metode statis seperti compareUnsigned, divideUnsigneddll telah ditambahkan ke kelas Integer untuk mendukung operasi aritmatika untuk integer yang tidak ditandatangani.

Perhatikan bahwa intvariabel masih ditandatangani ketika dideklarasikan tetapi aritmatika yang tidak ditandatangani sekarang dimungkinkan dengan menggunakan metode-metode di Integerkelas.


11
Agar adil, untuk banyak proyek persyaratan teknis tidak begitu ketat dan Anda memang mampu "membuang" memori seperti itu.
Simeon Visser

6
Saya tahu, saya juga mengerti tujuan asli Jawa. Tapi misalnya Smartphone tidak membuang dengan memori ekstra. Dan mereka biasanya menggunakan Java, sejauh yang saya tahu. Tapi yah, saya tidak ingin memulai perang antara programmer Java dan yang lainnya.
Tomáš Zato - Reinstate Monica

122
Bagi saya ini bukan hanya masalah membuang-buang uang. Ketika Anda bekerja pada level bit, unsigned lebih mudah untuk dikerjakan
Cruncher

24
Pada Java 8, ini tidak lagi benar . Di Java SE 8 dan yang lebih baru, Anda bisa menggunakan inttipe data untuk mewakili integer 32-bit yang tidak ditandatangani, yang memiliki nilai minimum 0dan nilai maksimum 2^32-1. - lihat docs.oracle.com/javase/tutorial/java/nutsandbolts/… dan docs.oracle.com/javase/8/docs/api/java/lang/Integer.html
8bitjunkie

2
@ 7SpecialGems: Saya telah memperbarui jawaban untuk memasukkan informasi itu. Yang sedang berkata, itu tidak mungkin untuk mendeklarasikan bilangan bulat yang tidak ditandatangani atau mengecualikan nilai negatif, itu hanya mungkin untuk menggunakan intseolah-olah itu tidak ditandatangani dengan menggunakan berbagai metode.
Simeon Visser

70

1
@stas Saya mengalami kesulitan dalam memahami penggunaan dan masalah besar karena memiliki kemampuan untuk menggunakan tipe data yang tidak ditandatangani. Dari berbagai sumber online yang saya baca, sepertinya berkisar hanya memperluas nilai maksimum, dan secara implisit menjamin bahwa itu adalah angka positif. Apakah pemahaman saya benar, atau adakah alasan utama lainnya? Juga, sekarang Integerkelas di Java 8 memungkinkan seseorang untuk menggunakan unsigned int, adalah perbedaan antara hanya dalam ruang dan kecepatan (karena dalam C / C ++ mereka primitif, sementara di Jawa, itu adalah pembungkus seluruh objek)
Abdul

2
@Abdul - ketika Anda bekerja pada level bit (biasanya karena Anda berinteraksi dengan perangkat keras) Anda perlu nilai untuk berperilaku dengan cara tertentu. yaitu - berguling setelah 11111111 hingga 00000000 dll. Menggunakan masuk di tempat yang tidak ditandatangani dapat merusak perhitungan CRC dll. Ini bukan penghenti acara, hanya buang-buang waktu.
Lorne K

3
@Lorne K: di Jawa, intterguling, meskipun sudah ditandatangani. Itu C / C ++ di mana unsigned berguling, tetapi masuk menyebabkan "Perilaku Tidak Terdefinisi" pada overflow. Jika "berguling" adalah satu-satunya masalah Anda, Anda tidak perlu tanda tangan. Saya kira, itulah sebabnya rutin CRC, dll. Bekerja di Jawa tanpa usaha ekstra. Dan itulah mengapa API baru hanya menambahkan penguraian, pemformatan, perbandingan, bagi, dan sisanya. Semua operasi lain, yaitu semua manipulasi bit, tetapi juga penjumlahan, pengurangan, penggandaan, dll. Tetap melakukan hal yang benar.
Holger

4
@Ciprian Tomoiaga: untuk menambahkan dengan rollover, pola bit input dan hasilnya tidak bergantung pada apakah Anda mengartikannya sebagai nomor yang ditandatangani atau nomor yang tidak ditandatangani. Jika Anda memiliki kesabaran, Anda dapat mencobanya dengan semua kombinasi 2⁶⁵…
Holger

3
@ Holger terima kasih atas penjelasannya! Memang, itu sebabnya kami menggunakan komplemen 2's. Saya memang mencobanya dengan beberapa kombinasi 2 ^ 8 ^^
Ciprian Tomoiagă

66

Apakah nilai dalam int ditandatangani atau tidak, tergantung pada bagaimana bit diinterpretasikan - Java menginterpretasikan bit sebagai nilai yang ditandatangani (tidak memiliki primitif yang belum ditandatangani).

Jika Anda memiliki int yang ingin Anda tafsirkan sebagai nilai yang tidak ditandatangani (mis. Anda membaca sebuah int dari DataInputStream yang Anda tahu berisi nilai yang tidak ditandatangani) maka Anda dapat melakukan trik berikut.

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

Perhatikan, penting bahwa heks literal adalah literal yang panjang, bukan literal int - maka 'l' pada akhirnya.


3
Bagi saya ini adalah jawaban terbaik ... Data saya berasal dari kartu NFC UID, yang dapat memiliki 4 atau 8 byte ... Dalam kasus 4 byte saya perlu melemparkannya ke int yang tidak ditandatangani, dan saya tidak bisa gunakan ByteBuffer.getLong karena itu bukan data 64-bit. Terima kasih.
Loudenvier

Kenapa harus panjang. Tidak bisakah Anda melakukan 0xFFFFFFdan mempertahankan int?
Singkirkan

19

Kami membutuhkan nomor unsigned untuk model MySQL unsigned TINYINT, SMALLINT, INT, BIGINTdi jOOQ , itulah sebabnya mengapa kami telah membuat jOOU , korban perpustakaan minimalis wrapper jenis untuk nomor unsigned integer di Jawa. Contoh:

import static org.joou.Unsigned.*;

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

Semua tipe ini meluas java.lang.Numberdan dapat dikonversi menjadi tipe primitif tingkat tinggi danBigInteger . Semoga ini membantu.

(Penafian: Saya bekerja untuk perusahaan di belakang perpustakaan ini)


Ini kedengarannya sangat nyaman! Terima kasih telah menyebutkan. :)
Lucas Sousa



2

Mungkin ini yang Anda maksud?

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

Anda mengorbankan sepersejuta detik waktu kinerja untuk mengetik malas dengan operator ternary alih-alih pernyataan if. Tidak baik. (bercanda)
ytpillai

5
Apakah Anda benar-benar berpikir, 2 * (long) Integer.MAX_VALUE + 2lebih mudah dipahami daripada 0x1_0000_0000L? Dalam hal itu, mengapa tidak sederhana return signed & 0xFFFF_FFFFL;?
Holger

2

Tampaknya Anda dapat menangani masalah penandatanganan dengan melakukan "logika DAN" pada nilai-nilai sebelum Anda menggunakannya:

Contoh (Nilai byte[] header[0]is 0x86):

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

Hasil:

Integer -122 = 134

2

Ada jawaban yang bagus di sini, tapi saya tidak melihat demonstrasi operasi bitwise. Seperti Visser (jawaban yang saat ini diterima) mengatakan, Java menandatangani bilangan bulat secara default (Java 8 memiliki bilangan bulat yang tidak ditandatangani, tetapi saya tidak pernah menggunakannya). Tanpa basa-basi lagi, mari kita lakukan ...

Contoh RFC 868

Apa yang terjadi jika Anda perlu menulis bilangan bulat yang tidak ditandatangani ke IO? Contoh praktisnya adalah ketika Anda ingin menampilkan waktu sesuai dengan RFC 868 . Ini membutuhkan bilangan bulat 32-bit, big-endian, tidak ditandatangani yang mengkodekan jumlah detik sejak pukul 12:00 AM 1 Januari 1900. Bagaimana Anda menyandikan ini?

Buat integer 32-bit Anda yang tidak ditandatangani seperti ini:

Deklarasikan array byte 4 byte (32 bit)

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

Ini menginisialisasi array, lihat Apakah array byte diinisialisasi ke nol di Jawa?. Sekarang Anda harus mengisi setiap byte dalam array dengan informasi dalam urutan big-endian (atau little-endian jika Anda ingin menghancurkan kekacauan). Dengan asumsi Anda memiliki waktu yang lama (bilangan bulat panjang 64 bit di Jawa) disebut secondsSince1900(Yang hanya menggunakan nilai 32 bit pertama, dan Anda telah menangani fakta bahwa Referensi tanggal 12:00 AM 1 Januari 1970), maka Anda dapat menggunakan logika DAN untuk mengekstrak bit dari itu dan menggeser bit-bit itu ke posisi (digit) yang tidak akan diabaikan ketika disatukan menjadi Byte, dan dalam urutan big-endian.

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

Kami my32BitUnsignedInteger sekarang setara dengan integer big-endian 32 bit yang tidak ditandatangani yang mematuhi standar RCF 868. Ya, datatype lama ditandatangani, tetapi kami mengabaikan fakta itu, karena kami menganggap bahwa secondsSince1900 hanya menggunakan 32 bit yang lebih rendah). Karena memasukkan panjang ke dalam byte, semua bit lebih tinggi dari 2 ^ 7 (dua digit pertama dalam hex) akan diabaikan.

Sumber yang dirujuk: Pemrograman Jaringan Java, Edisi ke-4.


1

Baru saja membuat potongan kode ini, yang mengubah "this.altura" dari negatif ke angka positif. Semoga ini bisa membantu seseorang yang membutuhkan

       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

Anda dapat menggunakan fungsi Math.abs (angka). Ini mengembalikan angka positif.


12
nitpick: not if you pass inMIN_VALUE
Dennis Meng

2
@ kyo722 Saya tidak bisa membayangkan bahwa ini akan mengembalikan nilai positif dalam kisaran primitif yang belum ditandatangani.
Florian R. Klein

1
nitpick # 2: tidak jika Anda lulus0
genisage
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.