簡體   English   中英

JAVA 和字節數組

[英]JAVA and byte arrays

我正在嘗試使用一個 API,其中有一個套接字用於通信。 請求由不同部分組成,其中之一是標頭,如下所示:

Fixed header: 2 bytes, fixed at 0xffff

通常我不擅長字節和流,因為我從未使用過它。 那么我應該如何創建所說的字節數組? 我試過以下

byte[] header = new byte[]{(byte)0xff, (byte)0xff};

但是它們每個字節都變成 -1,我相信這是因為 0xFF 轉換為 255,這超出了有符號字節范圍(-128 到 +127),但是我該如何創建這樣的標頭?

你剛剛做到了。

最后,計算機只知道比特。 剩下的就是代碼和查看它的人所做的。 位是 0 或 1。如果您購買了具有 4GB RAM 的計算機,那么您的計算機可以記住其中的 34359738368。

這有點笨拙,因此 AMD、英特爾、台積電或任何烘焙您芯片的人都將芯片融入芯片設計中,芯片將它們以 8 個為一組(對於某些工作,以 64 個或更高為一組)。 但這就是它結束的地方。 這只是一點點,真的。 負數? 那是什么? 2? 你說的這2個是什么。 我只知道0和1。

所以這也很笨拙,所以我們人類不想說:這個字節持有值 00000101。我們只會說“持有 5”。

bits     = decimal
00000000 = 0
00000001 = 1
00000010 = 2
00000011 = 3
00000100 = 4
00000101 = 5
... and so on

太好了,但是 -1 呢? 我們只有01 沒有 - 那么我們如何做到這一點?

這就是它變得有趣的地方。 這是一個約定,而不是計算機中的東西。 有一種叫做二進制補碼的東西:我們都同意檢查第一位。 如果它是 1,那么我們將稱之為-X ,其中 X 是通過應用以下算法找到的:翻轉每一位(所有零變為 1,所有 1 變為零),然后將其加 1。

11111011 = -5.

Why? Well, flip every bit: 00000100
then add 1 to it         : 00000101

which is 5.

但這立即吃掉了我們可以代表的一半。 畢竟,我們現在可以存儲在一個字節中的最大數字是 127: 01111111 ,也就是 127。如果我們給這個數字加 1,那么我們得到10000000 ,但是嘿,它以 1 位開頭,所以假設我們都是同意這意味着它是負數,這意味着1000000是 -128(有點奇怪)。

有時這很煩人或不值得。 所以有時我們都同意這個數字根本不能是負數1000000只是 128。而11111111只是 255。

電腦不知道。 255 是11111111 ,-1 也是。 那么11111111什么? 電腦不知道。 它甚至不知道2是什么。 它只知道零和一,就計算機而言, 11111111就是它。 (數學計算得出 + 和 - '只是工作',無論我們是否規定這些數字是否被視為有符號的二進制補碼,很酷,是吧?試試吧!如果11111011既是 -5 11111011是 251,取決於一個閱讀關數的意見,會發生什么?-5 + 2是-3。251 + 2是253 -3253歸結為位的順序相同。只是一個例子,這是順便說一下,為什么我們做了奇怪的“翻轉所有位並加1”的東西。這樣+和-就可以工作,你不需要傳遞你是否考慮“有符號”或“無符號”位。

在java中,除char (它是一種數字類型。你認為它代表一個字符,但實際上不是)之外的所有數字類型都是有符號的。 byte是“有符號的 8 位數字”(因此,可以表示從-128+127 ,含)。 char 是唯一的例外,它是一個“無符號的 16 位數字”,因此可以保存065535 ,包括065535 只是如果你調用System.out.println((char) 65); , println 方法會將該數字解釋為:“在 unicode 表中查找並打印您在那里找到的任何內容”,因此打印 'A'。 這是該特定 println 方法的源代碼的一部分,它與 java 中的char類型無關,它只是“0 到 65535 之間的數字”。

因此,當您在 java 中打印包含0xFF, 0xFF字節數組時,因為 java 同意我們認為它已簽名,所以它會打印 -1, -1。 但這只是 0xFF、0xFF 的 java-ese。 您的字節數組包含 0xFF, 0xFF 因為在位級別 -1 和 255 是完全相同的數字 無論如何,對於字節。 其他的(char、short、int、long)則不然。

回顧一下:

byte x = (byte) 200;
byte x = (byte) 0xC8;
byte x = -56;

在所有這些情況下, x 最終保持位11001000 沒有辦法區分 你不能問系統:那么,呃,這個 x 是等於 200、0xC8 還是 -56? 是用什么來設置的? 因為計算機不知道 - 編譯器將上述所有代碼轉換為完全相同的最終結果,即 11001000。

255-1。

好吧,首先您必須知道在 Java 中所有整數類型都是有符號的。 這意味着保留最高有效位來表示符號。 這就是為什么在 Java 中常量Byte.MAX_VALUE說它可以達到 127。

現在,這意味着您可以在一個字節中存儲 8 位,但是如果您碰巧打開了符號位,那么您存儲的任何內容都將被 Java 表示為負數。

由於0xff打開所有字節位(即11111111 )而不是像您期望的那樣獲得255 ,因此您獲得的是 -1,因為該數字在 Java 中表示 -1。

也許為了理解它,我可以向您展示這些位在 Java 中是如何工作的。 想象一種只有 4 位的稱為靈活的類型,其中最高有效位保留用於符號。

如果 Java 存在的話,它會是這樣的:

Imaginary Signed Type: Nimble (4 bits)

Dec. Bin.  Hex.
--------------------
+0   0000  0x0   
+1   0001  0x1
+2   0010  0x2
+3   0011  0x3
+4   0100  0x4
+5   0101  0x5
+6   0110  0x6
+7   0111  0x7
-8   1000  0x8
-7   1001  0x9
-6   1010  0xA
-5   1011  0xB
-4   1100  0xC
-3   1101  0xD
-2   1110  0xE
-1   1111  0xF

注意那些最高有效位的數字是如何變成負數的。 如果這個靈活是無符號類型,那么它不會有負數,它可以達到 15。

這就是為什么 Java 字節從 -128 到 127,而不是您期望的最多 255。

現在,當涉及到創建字節數組以發送到流時,也許不是自己創建字節數組,您可以將套接字輸出流包裝到類型感知流,如DataOuputStream ,它允許您發送特定類型的數據.

例如:

try(DataOutputStream out = new DataOutpuStream(socket.getOutputStream())) {
   dOut.writeByte((byte)0xff);
   dOut.writeByte((byte)0xff);
}

這樣您就可以避免必須創建標題數組的所有困難。

但最重要的是,如果沒問題,你就是數組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM