[英]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 呢? 我們只有0
和1
。 沒有 - 那么我們如何做到這一點?
這就是它變得有趣的地方。 這是一個約定,而不是計算機中的東西。 有一種叫做二進制補碼的東西:我們都同意檢查第一位。 如果它是 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 -3
和253
歸結為位的順序相同。只是一個例子,這是順便說一下,為什么我們做了奇怪的“翻轉所有位並加1”的東西。這樣+和-就可以工作,你不需要傳遞你是否考慮“有符號”或“無符號”位。
在java中,除char
(它是一種數字類型。你認為它代表一個字符,但實際上不是)之外的所有數字類型都是有符號的。 byte
是“有符號的 8 位數字”(因此,可以表示從-128
到+127
,含)。 char 是唯一的例外,它是一個“無符號的 16 位數字”,因此可以保存0
到65535
,包括0
到65535
。 只是如果你調用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.