Java 從流中讀取byte的奇怪現象,出現負值,詳解(經典 重要)

來源:https://blog.csdn.net/xingtanzjr/article/details/50898122

https://blog.csdn.net/zhaomengszu/article/details/54562056

其實一點都不奇怪,下面我們來詳細分析

首先看下面一段代碼,代碼的意思是將128寫入到文件中,再從文件中讀出一個byte輸出

    File f = new File("f1");
    FileOutputStream fos = new FileOutputStream(f);
    fos.write(128);
    fos.close();

    FileInputStream fis = new FileInputStream(f);
    int a = fis.read();
    System.out.println(a);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

輸出結果爲:

128

這符合我們的直觀感覺,寫入128,讀出來也是128

下面我們修改一下代碼,將數據度入到byte數組裏,看看輸出會是什麼樣子,代碼如下

    File f = new File("f1");
    FileOutputStream fos = new FileOutputStream(f);
    fos.write(128);
    fos.close();

    FileInputStream fis = new FileInputStream(f);
    byte[] b = new byte[1];
    fis.read(b, 0, 1);
    System.out.println(b[0]);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

輸出結果爲

-128

好了,“奇怪”的現象出現了,這是爲什麼呢?

首先,我們需要了解一些基礎知識,在Java中,byte的範圍爲 -128 ~ 127,並沒有128這個數值;其次,讀者需要了解一下負數在Java中如何表示(即原碼、反碼、補碼的相關知識,請讀者自行谷歌)。

下面,我們來分析一下出現 -128 的原因:

首先,fos.write(128) 表示寫入 “128” 所代表的字節,即 1000 0000,也就是說,文件中當前包含一個字節,8位依次爲 1 0 0 0 0 0 0 0

當我們調用fis.read()時,該方法會返回一個無符號byte,也就說直接將1000 0000翻譯爲128,大家可以去看該方法的說明,返回值的範圍爲0 ~ 255;所以我們得到了 128 的輸出;

當我們調用fis.read(b, 0, 1)時,相當於把文件中第一個字節讀入到了b[0]中,此時b[0]的二進制表示爲1000 0000,根據負數在Java中的表示方法,我們可以計算出,該二進制序列的數值爲 -128,也就是說這個過程並沒有將其轉化爲無符號數值的過程,所以我們得到了 -128 的輸出。

那麼,我們如何解決這個問題呢?

首先,我們需要看一下fos.write(int a)這個方法,它的功能是寫入a代表的byte值,也就是說,該函數實際上是將a 的後八位寫入到文件中 , 所以作者建議在使用該方法時,爲了避免產生歧義,a 的範圍最好在 0 ~ 255 之間,初學者最好在 0 ~ 127 之間。(具體原因可以結合負數的表示規則自己想想哦~)。

迴歸正題,我們如何解決上文中的問題呢,即 “寫入128、讀出-128” 的問題,我們可以用下面的代碼來解決。

    File f = new File("f1");
    FileOutputStream fos = new FileOutputStream(f);
    fos.write(128);
    fos.close();

    FileInputStream fis = new FileInputStream(f);
    byte[] b = new byte[1];
    fis.read(b, 0, 1);
    System.out.println(b[0] & 0xff);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

也就是說,用b[0] & 0xff的方法得到b[0]的無符號值。

插入一個小問題,就是,b[0] | 0xff得到的是一個負值,而 & 得到的卻是一個正值。這裏根據作者的猜測,可能是如下原因,主要和 & 運算的步驟有關:

進行 b[0] & 0xff運算時的步驟如下:

  1. 因爲0xff默認應該用int來保存,所以首先將 b[0] 強制轉化爲 int 類型表示,b[0] 的數值爲-128,所以其二進制表示爲11111111 11111111 11111111 10000000
  2. 0xff的二進制表示爲 00000000 00000000 00000000 11111111
  3. 這兩個數做 & 運算後,得到 00000000 00000000 00000000 10000000,其表示的值爲128

“或 運算”的過程類似,讀者可以自己推理一下

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章