为什么使用打印流打印字节(数字数据类型)会给我字符?

Why does printing bytes (a numeric data type) using a print stream give me characters?

为什么编译下面的代码会得到一个ASCII码值:GHI?我以为 byte 是数字数据类型?请参阅下面的代码:

import java.io.*;

public class PrintStreamDemo {

   public static void main(String[] args) {
    
      byte c[] = {70, 71, 72, 73, 74, 75, 76};
      // create printstream object
      PrintStream ps = new PrintStream(System.out);
    
      // write bytes 1-3
      ps.write(c, 1, 3);
    
      // flush the stream
      ps.flush();
  }
}

I thought byte is a numerical data type?

对于Java Language Specification来说,byte确实是一个数字数据类型,char:

也是

The types of the Java programming language are divided into two categories: primitive types and reference types. The primitive types (§4.2) are the boolean type and the numeric types. The numeric types are the integral types byte, short, int, long, and char, and the floating-point types float and double.

char代表一个字符”的意思是一个有用的抽象,它的范围正好是一个UTF-16字符的范围。但是对于计算机来说,char 只是 16 个 1 和 0,而 byte 只是 8 个 1 和 0。如何解释它们取决于解释器。

当您使用 System.out.println() 打印 byte 时,字节首先被转换为 int,该方法将它们解释为数字 1,这就是为什么 System.out.println(70b) 打印“70”而不是 G.

另一方面,您的控制台 运行 这个程序将它接收到的字节解释为以 UTF-8 编码的字符串。 System.out,您的 ps 连接到,write 将字节发送到控制台。这就是为什么 70 被打印为“G”等的原因。


1 如果您查看 println 实际执行的源代码,您会发现在最底层,它还调用 write(byte[], int, int) ,只是不写入字节 70。而是写入字节 55 和 48,分别表示字符“7”和“0”。

首先,System.out已经是PrintStream了。所以用另一个 PrintStream 包装它是没有意义的。

其次,printwrite在Java中不是一回事。甚至在 PrintStream.

上也不行

第三,虽然byte在Java中是数值类型,char也是。因此,任何类似于“它是一个数字,因此必须打印为数字”的推理在 Java 中都不成立。相反,您需要查看 API 规范的详细信息。


这里实际发生的是 PrintStream.write(byte[], int, int) 将字节从数组写入底层 OutputStream 而没有进行任何格式化或字符集编码,如 javadoc 中所述这个方法。

在很多字符集编码中,字节值70、71、72对字符G、H、I进行编码。(代码70、71、72用ASCII表示这些字母,很多编码都“借用”了ASCII他们前 128 个代码的编码。)

现在,可以推测,您的 JVM 使用的默认字符集编码是上述编码之一...所以您会在控制台上看到“GHI”输出。

然而……并不是所有的字符编码都是这样的。例如,如果您的平台的默认编码设置为 16 位编码,字节 7071 实际上代表单个 Unicode 代码点 U+4647 ...这是一个中文字符。


如果您改用 ps.write(c[i])ps.print(c[i]),您会得到相同的行为。这将分别调用 PrintStream.write(int)PrintStream.print(char)。并且最终都将字节视为字符的表示1.

如果要使用 PrintStream 打印格式化为数字的字节,则需要将其转换为 int:

  ps.print((int) c[1]);

PrintStream.print(int) 方法打印其参数的十进制表示。


1 - 以不同的方式。 PrintStream.write(int) 只写字节而不考虑编码。 PrintStream.print(char) 应用了正确的编码。根据您正在打印的字节和字符编码,这两个调用可能会给出不同的结果。

Byte 和 char 是数字数据类型,这并不意味着它们类似于 int 或 float... 字节以字节格式存储数据。

要从字节数组读取数据,请使用 ByteArrayInputStream。

import java.io.*;

public class PrintStreamDemo {

   public static void main(String[] args) {
    
      byte c[] = {70, 71, 72, 73, 74, 75, 76};

      // Create the new byte array input stream  
      ByteArrayInputStream byt = new ByteArrayInputStream(buf);  
    
      // Print data
      int k = 0;  
      while ((k = byt.read()) != -1) {  
         //Conversion of a byte into character  
         char ch = (char) k;  
         System.out.println("ASCII value of Character is:" + k + "; Special character is: " + ch);  
      }  
      
      // flush the stream
      byt.flush();
  }
}