首页 > 解决方案 > 在 java 中,FileInputStream 中的 read() 方法为何不会抛出“不兼容的类型:可能的有损转换”?

问题描述

我目前正在阅读 Java I/O教程并且很难理解 FileInputStream 类的 read() 方法。我知道每个文档 read() 方法从流中读取数据的“字节”并返回一个表示字节的整数(在 0 到 256 之间)或 -1 如果它到达文件末尾。

java中的字节范围在-128到127之间,所以,当我编辑xanadu.txt并添加ASCI符号“ƒ”(十进制值为131)时,java不会通过抛出值为131的错误来抱怨超出字节(-128 和 127)定义的范围?当我尝试使用文字对此进行测试时,我得到了两个不同的结果。

以下作品:

byte b = 120;
int c = b;
System.out.println((char)c);

Output: x

但这不起作用(即使它在添加到 xanadu.txt 时起作用):

byte b = 131;
int c = b;
System.out.println((char)c);

Output: error: incompatible types: possible lossy conversion from int to byte
        byte b = 131;

我尝试使用字节显式转换:(这怎么可能?)

byte b = (byte)131;
int c = b;
System.out.println((char)c);

Output: テ

在 I/O 流方面,我完全是新手,请有人帮助我理解它。

编辑:原来我缺乏关于类型转换概念的知识,特别是在理解“加宽”和“收窄”之间的区别方面。阅读有关这些概念的更多信息有助于我理解为什么显式(又名缩小)强制转换有效。

请允许我解释一下:查看第三个代码块,我将文字“131”显式转换为字节类型。如果我们要将文字 131 转换为 32 位有符号 2 的补码整数的二进制形式,我们将得到 00000000 00000000 00000000 10000011,即 32 位或 4 个字节。回想一下,Java 数据类型 'byte' 只能保存 8 位有符号 2 的补码整数,因此 131 超出范围,因此我们得到错误“从 int 到字节的可能有损转换”。但是,当我们明确地将其转换为字节时,我们正在“切断”或正确的术语将二进制“缩小”到 8 位整数。因此,当我们这样做时,生成的二进制文件是 10000011,即十进制值 -125。由于 -125 在 -128 和 127 的范围内,因此 byte 接受和存储它没有问题。现在,当我尝试在 int c 中讲述 byte 的值时,会发生隐式或“加宽”转换,其中 8 位 10000011 的二进制形式的 -125 转换为 32 位的二进制形式的等效 -125 11111111 11111111 11111111 10000011。最后,system.out 正在尝试输出 (char)c 的值,这是另一个显式或“缩小”转换,它试图从 32 位有符号缩小到 16 位无符号。转换完成后,我们得到二进制形式的 11111111 10000011。现在,当这个二进制文件被java转换为字符形式时,它返回テ。out 试图输出 (char)c 的值,这是另一个显式或“缩小”转换,它试图从 32 位有符号缩小到 16 位无符号。转换完成后,我们得到二进制形式的 11111111 10000011。现在,当这个二进制文件被java转换为字符形式时,它返回テ。out 试图输出 (char)c 的值,这是另一个显式或“缩小”转换,它试图从 32 位有符号缩小到 16 位无符号。转换完成后,我们得到二进制形式的 11111111 10000011。现在,当这个二进制文件被java转换为字符形式时,它返回テ。

我可以总结说它有助于将所有内容转换为二进制形式并从那里开始。但请确保您了解编码和2 的补码

标签: javaiostreambyte

解决方案


我不知道你从哪里得到值 131,但就我而言,LATIN SMALL LETTER F WITH HOOK (ƒ) 不在原始 ASCII 字符集中,而是在扩展 ASCII 中,十进制值为 159 . 见这里。它还以 UTF-16(Javachar的编码方式)编码为十六进制 192(十进制值 402)。

首先,确保您的文本文件以扩展的 ASCII 编码,而不是 UTF-8(这是最可能的编码)。FileInputStream然后你可以使用read文件,你会得到159.

请注意,这159超出了 Javabyte类型的范围。这很好,因为read返回一个int. 但是,如果文本文件以 UTF-8 编码,则 ƒ 以 2 个字节编码,因此read一次读取一个字节。

你的第二个代码块不起作用,因为正如你所说,byte从 -128 到 127,所以 131 显然不适合。

您的第三个代码块将 131 强制转换为一个字节,这会导致溢出并且值“回绕”为 -125。b并且c都是-125。当您将其转换为 achar时,它变为 65411,因为此转换涉及首先将整数填充为 16 位,然后将其视为无符号整数。

FileInputStream.read当您使用而不是自己进行这些转换时,这一切都起作用的原因是因为read实际上返回的是inta ,而不是 a byte。只是int它返回的总是在-1~255的范围内。这就是为什么我们说“read返回一个字节”,但它的实际返回类型是int


推荐阅读