Int İşaretsiz Bayta ve Geri Nasıl Dönüştürülür


93

Bir sayıyı işaretsiz bayta dönüştürmem gerekiyor. Sayı her zaman 255'ten küçük veya eşittir ve bu nedenle bir bayta sığar.

Ayrıca bu baytı o sayıya geri dönüştürmem gerekiyor. Bunu Java'da nasıl yaparım? Birkaç yol denedim ve hiçbiri işe yaramadı. İşte şimdi yapmaya çalıştığım şey:

int size = 5;
// Convert size int to binary
String sizeStr = Integer.toString(size);
byte binaryByte = Byte.valueOf(sizeStr);

ve şimdi bu baytı sayıya geri dönüştürmek için:

Byte test = new Byte(binaryByte);
int msgSize = test.intValue();

Açıkçası, bu işe yaramıyor. Bazı nedenlerden dolayı, her zaman sayıyı dönüştürür 65. Herhangi bir öneri?


Bu yöntemi de denedim: crazysquirrel.com/computing/java/basics/… - çalışmıyor.
darksky

Yanıtlar:


205

Bir bayt her zaman Java'da imzalanır. İmzalanmamış değerini ikili ve 0xFF ile yazarak alabilirsiniz, ancak:

int i = 234;
byte b = (byte) i;
System.out.println(b); // -22
int i2 = b & 0xFF;
System.out.println(i2); // 234

1
Baytta istediğiniz sayıyı saklıyor. Java, bunu imzasız numara yerine imzalı bir numara olarak kabul eder. Ancak her bit, sanki işaretsiz bir numaraymış gibi aynıdır. Dizeyi bayta dönüştürmeniz, ilgisiz başka bir sorudur. Yeni bir soruda ayrı olarak gönderin.
JB Nizet

1
int'inizi geri almak için getInt kullanın ve int'i bir bayt olarak dönüştürün. İnt, int'dir. Nereden geldiği önemli değil.
JB Nizet

1
Java baytları imzalandı mı? Yüce Tanrım, ne korku.
Nyerguds

19
Neden bit tabanlı ve 0xFFişaretsiz bir tamsayı ile sonuçlanır? Bazı açıklamalar gerçekten yardımcı olabilir.
user462455

2
Java 8 aynı yöntemi kullanır: public static int toUnsignedInt (byte x) {return ((int) x) & 0xff; }
Daniel De León

57

Java 8 sağlar Byte.toUnsignedIntdönüştürmek byteiçin intimzasız dönüşüm ile. Oracle'ın JDK'sında bu, return ((int) x) & 0xff;HotSpot'un bu kalıbı nasıl optimize edeceğini zaten anladığı için uygulanıyor, ancak diğer VM'lere de dahil edilebilir. Daha da önemlisi, bir çağrının ne yapacağını anlamak için önceden bilgi toUnsignedInt(foo)gerekmez.

Toplamda Java 8, dönüştürmek byteve shortimzasız hale getirmek için yöntemler sağlarint ve longve intişaretsiz için long. Dönüştürmek için bir yöntem byteimzasız için shortyapıldı kasten ihmal JVM yalnızca aritmetik sağladığı için intve longher neyse.

Bir int'i bir bayta dönüştürmek için, sadece bir çevrim kullanın: (byte)someInt . Ortaya çıkan daralan ilkel dönüşüm , son 8 bit dışında tümünü atacaktır.


7

Beklenen bir 8 bitlik değeri işaretli bir int'ten işaretsiz bir değere dönüştürmeniz gerekiyorsa, basit bit kaydırmayı kullanabilirsiniz:

int signed = -119;  // 11111111 11111111 11111111 10001001

/**
 * Use unsigned right shift operator to drop unset bits in positions 8-31
 */
int psuedoUnsigned = (signed << 24) >>> 24;  // 00000000 00000000 00000000 10001001 -> 137 base 10

/** 
 * Convert back to signed by using the sign-extension properties of the right shift operator
 */
int backToSigned = (psuedoUnsigned << 24) >> 24; // back to original bit pattern

http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

intTemel tür dışında bir şey kullanıyorsanız , açıkça vardiya miktarını ayarlamanız gerekir: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

Ayrıca, bytetürü kullanamayacağınızı unutmayın , bunu yapmak, diğer yanıtlayıcılar tarafından belirtildiği gibi imzalı bir değerle sonuçlanacaktır. 8 bitlik işaretsiz bir değeri temsil etmek için kullanabileceğiniz en küçük ilkel tür, bir short.


3

Integer.toString(size)Senin tamsayı karakter gösterimi içine çağrı dönüştürür, char, yani '5'. ASCII gösterimi karakterin 65 değeridir.

İlk önce dizeyi bir tamsayı değerine geri ayrıştırmanız gerekir, örn. Integer.parseInt , orijinal int değerini geri almak için .

Sonuç olarak, imzalı / işaretsiz bir dönüştürme için, String@JB'nin önerdiği gibi resimden uzak durmak ve bit manipülasyonunu kullanmak en iyisidir.


Yani böyle mi? (Burada hala 65 oluyor)String sizeStr = Integer.toString(size); int sizeInt = Integer.parseInt(sizeStr); byte binaryByte = Byte.valueOf((byte) sizeInt);
darksky

@Nayefc, siz yorumunuzu yazarken cevabımı güncelledim :-)
Péter Török

Pekala teşekkürler! Bazı nedenlerden dolayı HALA 65 yazdırıyor. Ne anlama geliyor? Sadece 65 gösteriyorsa, aslında baytta depolanan şey o zaman anlamıyorum. Ayrıca lütfen sorumu kontrol edin, düzenledim ve dizelerin dönüşümü hakkında bir bölüm ekledim :)
darksky

@Nayefc, metnin içerdiği karakterlerinString.getBytes() ASCII değerlerini verir, rakamların sayısal değerlerini değil. Yukarıda ima ettiğim gibi, dizeyi sayısal bir değer olarak ayrıştırmanız gerekir .
Péter Török

1
@Nayefc, bu aslında tamamen farklı bir soru. Ve AFAIS işe yaramalı. Dönüşümün gerçek girdisi ve çıktısı ile vakayı yeniden oluşturmak için tam kod dahil olmak üzere yeni bir soru oluşturun.
Péter Török

3

Çözüm iyi çalışıyor (teşekkürler!), Ancak yayın yapmaktan kaçınmak ve düşük seviyeli çalışmayı JDK'ya bırakmak istiyorsanız, int'lerinizi yazmak için bir DataOutputStream ve bunları tekrar okumak için bir DataInputStream kullanabilirsiniz. Bunlar otomatik olarak imzasız olarak kabul edilir. bayt sonra:

İnt'leri ikili bayta dönüştürmek için;

ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
int val = 250;
dos.write(byteVal);
...
dos.flush();

Onları tekrar okumak:

// important to use a (non-Unicode!) encoding like US_ASCII or ISO-8859-1,
// i.e., one that uses one byte per character
ByteArrayInputStream bis = new ByteArrayInputStream(
   bos.toString("ISO-8859-1").getBytes("ISO-8859-1"));
DataInputStream dis = new DataInputStream(bis);
int byteVal = dis.readUnsignedByte();

Esp. ikili veri formatlarını işlemek için kullanışlıdır (örneğin düz mesaj formatları, vb.)


3

Dışında char , Java'daki diğer tüm sayısal veri türleri imzalanır.

Daha önceki bir cevapta söylendiği gibi, andile bir işlem yaparak işaretsiz değeri elde edebilirsiniz 0xFF. Bu cevapta bunun nasıl olduğunu açıklayacağım.

int i = 234;
byte b = (byte) i;
System.out.println(b);  // -22

int i2 = b & 0xFF;      
// This is like casting b to int and perform and operation with 0xFF

System.out.println(i2); // 234

Makineniz 32 bit ise, intveri türünün değerleri depolaması için 32 bit olması gerekir.bytesadece 8 bite ihtiyaç duyar.

intDeğişken i(32-bit tamsayı olarak), aşağıdaki gibi hafıza ile temsil edilir.

0{24}11101010

Ardından bytedeğişken bşu şekilde temsil edilir:

11101010

As byteler imzasız olan bu değer temsil-22 . (Bellekte negatif tam sayıların nasıl temsil edileceği hakkında daha fazla bilgi edinmek için 2'nin tamamlayıcısını arayın)

O zaman eğer döküm yaparsanız int, yine de olacaktır -22çünkü döküm bir sayının işaretini korur.

1{24}11101010

İle gerçekleştirme işleminin dönüştürülen 32-bitdeğeri .band0xFF

 1{24}11101010 & 0{24}11111111
=0{24}11101010

O zaman 234cevabı alırsın .


1

Çok geç de olsa JB Nizet'in verdiği çözümün neden işe yaradığını açıklığa kavuşturmak için bu konudaki girdimi vermek istiyorum. Bir bayt ayrıştırıcı üzerinde çalışırken ve dize dönüşümünü kendim yaparken bu küçük soruna rastladım. Bu java belgesinin söylediği gibi, daha büyük boyutlu bir integral türünden daha küçük boyutlu bir integral türüne kopyaladığınızda:

https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3 İşaretli bir tamsayının bir integral T türüne daraltılmış bir dönüşümü, n en düşük hariç hepsini atar sıra bitleri, burada n, tip T'yi temsil etmek için kullanılan bit sayısıdır.Numerik değerin büyüklüğü hakkındaki olası bilgi kaybına ek olarak, bu, sonuçtaki değerin işaretinin giriş değerinin işaretinden farklı olmasına neden olabilir. .

Bu java dokümanı https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html baytının dediği gibi bir baytın integral bir tür olduğundan emin olabilirsiniz : Bayt veri türü 8 bitlik imzalı bir ikidir tamamlayıcı tamsayı.

Yani bir tamsayıyı (32 bit) bir bayta (8 bit) çevirme durumunda, bu tamsayının sonuncusunu (en az önemli 8 biti) verilen bayt değişkenine kopyalarsınız.

int a = 128;
byte b = (byte)a; // Last 8 bits gets copied
System.out.println(b);  // -128

Hikayenin ikinci kısmı, Java tekli ve ikili operatörlerinin işlenenleri nasıl teşvik ettiğini içerir. https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2 Genişletme ilkel dönüştürme (§5.1.2), işlenenlerden birini veya her ikisini de belirtildiği gibi dönüştürmek için uygulanır aşağıdaki kurallara göre:

İşlenenlerden biri double türündeyse, diğeri double türüne dönüştürülür.

Aksi takdirde, işlenenlerden biri float tipindeyse, diğeri float'a dönüştürülür.

Aksi takdirde, işlenenlerden biri long türündeyse, diğeri long'a dönüştürülür.

Aksi takdirde, her iki işlenen de int türüne dönüştürülür.

İntegral türü int ve / veya daha düşük ile çalışıyorsanız, int türüne yükseltileceğinden emin olabilirsiniz.

// byte b(0x80) gets promoted to int (0xFF80) by the & operator and then
// 0xFF80 & 0xFF (0xFF translates to 0x00FF) bitwise operation yields 
// 0x0080
a = b & 0xFF;
System.out.println(a); // 128

Ben de bunun etrafında kafamı kaşıdım :). Bunun için burada rgettman tarafından iyi bir cevap var. Java'daki bitsel operatörler yalnızca tamsayı ve uzun için mi?


0

İlkel sarmalayıcı sınıflarını kullanmak istiyorsanız, bu işe yarayacaktır, ancak tüm java türleri varsayılan olarak imzalanır.

public static void main(String[] args) {
    Integer i=5;
    Byte b = Byte.valueOf(i+""); //converts i to String and calls Byte.valueOf()
    System.out.println(b);
    System.out.println(Integer.valueOf(b));
}

0

BigInteger ile baytları ve işaretsiz tam sayıları işleme:

byte[] b = ...                    // your integer in big-endian
BigInteger ui = new BigInteger(b) // let BigInteger do the work
int i = ui.intValue()             // unsigned value assigned to i

Bu işaretsiz değil, SIGNED tam sayıya dönüşür ...
Pedro

-1

Java 7'de

public class Main {
    public static void main(String[] args) {
        byte b =  -2;
        int i = 0 ;
        i = ( b & 0b1111_1111 ) ;
        System.err.println(i);
    }
}

sonuç: 254

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.