byte arr[] = new byte[] {56, 99, 87, 77, 73, 90, 105, -23, -52, -85, -9, -55, -115, 11, -127, -127};
String s= new String(arr);
Arrays.equals(arr, s.getBytes())); // returns false
为什么数组不相等?我希望getBytes()
返回原始的字节数组。
下面的构造函数将读取byte
数组并根据默认字符集对其进行解码。
new String(arr);
所以当你这么做的时候
String s= new String(arr);
s.getBytes()
bytes()
再次返回之前根据默认字符集解码的数组。
如果使用调试器进行检查,可以看到新字符串(字节[])
方法如何适用于UTF-8
默认字符集。您将看到字节{-127}
被解码为{-17,-65,-67}
,因为-127
作为字节对Utf-8
无效。所以{-127}
被解码成{-17,-65,-67}
,因为这代表了Utf-8的替换字符-
实际上,
字节
数组的任何元素如果不能作为有效的Utf-8
字符进行匹配,当这是默认字符集时,它就会被转换成{-17,-65,-67}
,这是�.
在您的示例中,以下字节
{-9,-127,-23}
对于Utf-8
字符集无效。所以之前的3个元素数组被转换为��� 在字节数组中,它再次由{-17,-65,-67,-17,-65,-67,-17,-65,-67}表示
你似乎认为字节和字符是可以互换的。
事实并非如此。
要将字符转换成字节,您需要使用字符集编码对字符进行编码。要将字节转换成字符,您需要使用字符集编码对它们进行解码。没有字符集编码,就没有将一个字符转换成另一个字符的事情。
过渡字节-
这里使用的方法(包括str.getBytes
和new String(byteArr)
)都使用“平台默认编码”。从JDK18开始,它被保证是UTF-8(从而保证它不会正常工作),在那之前,它是系统默认编码的内容,我们不知道。
US-ASCII不起作用,因为US_ASCII只将所有字节的子集定义为“有效”:0-126。大多数字节(所有字节都带有负号)都不是有效的ASCII码。
UTF-8不能工作,因为并非所有字节序列都是有效的UTF-8。换句话说,有些字节序列不能用UTF_8产生。
更重要的是,整个原则都被打破了。即使你知道它是ISO-8859-1,你想通过这样做实现什么?您可以将任意字节数组转换为ISO-8859-1,然后再转换回来,而不会丢失任何内容,但这有什么意义呢?你可以很容易地用NUL字符、制表符、空格、“铃铛”音和其他奇怪的声音产生造成破坏的字符串。这是你永远都不想打印的字符串。这就提出了一个问题:那你为什么想要一个呢?
对于这个问题,只有一个合理的答案,那就是:我希望通过一个只支持字符串的媒体来传输这些字节。例如,我有一些原始字节,我想把它们放在电子邮件中,或者放在jira罚单的表单字段中,或者诸如此类的傻事中,出于某种原因,附件不是这个选项。或者我想把它塞进一个URL(https://www.foo.bar/?q=raw-此处为字节
)。
这样做有两个答案,都不涉及新字符串(byteArr):
任何原始字节都可以简单地转换为十六进制表示:255(或-1,在有符号字节形式中,它是相同的)转换为FF
。1变为01-所有字节的长度始终正好为2个字符。你可以使用:
byte f = -1;
String nibbled = String.format("%02X", (int) f);
System.out.println(nibbled); // prints 'FF'
单个字母/数字(0-9A-F。从技术上讲,这只是一个数字,在十六进制中,a-F也是数字)被称为“半字节”(因为它是半字节,请看。男孩,这些术语发明时的60年代是一个笑话,不是吗)。
这有点低效;一个由X字节组成的字节数组会变成一个由2*X个字符组成的字符串(每个字符可能需要2个字节,例如,如果它是UTF-16编码的,那么总效率为25%,哎哟)。但它的可读性和通用性都很低。它适用于短字节(小于500字节左右)数组。
另一个优点是,如果可以读取十六进制,并且如果有符号,则可以读取2的补码,则可以查看字符串并知道数据是什么,这并不太困难。
Base64是一个简单的编码方案,它定义了64个“安全”字符,你知道这些字符会安全地“存活”,而不会被损坏或误解。这给了你每个字符6位的数据。字节是8,所以你可以用这种方法把3个字节“塞进”4个字符;例如,一个900字节的数组变成1200个字符。
Java内置了base64编码/解码。
byte arr[] = new byte[] {56, 99, 87, 77, 73, 90, 105, -23, -52, -85, -9, -55, -115, 11, -127, -127};
String s = Base64.getEncoder().encodeToString(arr);
// s is all ASCII chars and safe to include just about everywhere.
// URL parameter, emails, web forms, you name it.
byte[] arr2 = Base64.getDecoder().decode(s);
Arrays.equals(arr, arr2); // true, guaranteed.
Base64稍微复杂一些,你不能再盯着一个Base64字符串,只看字节矩阵样式。但它比半字节形式更高效:效率为75%(如果底层字符每个字符占用2字节,即使用UTF-16,则效率为37.5%)。
这取决于您的Charset.defaultCharset()
。这决定了如何解释字节。负值可能是表示代码点的非规范方式。
(看这个伟大的答案:https://stackoverflow.com/a/7934397/461499)
然后,将getBytes()
重新解释为字符串
将是标准的方法,并将返回true
System.out.println(Charset.defaultCharset()); //UTF-8 here :)
byte arr[] = new byte[] {56, 99, 87, 77, 73, 90, 105, -23, -52, -85, -9, -55, -115, 11, -127, -127};
String s= new String(arr);
System.out.println(s);
// [56, 99, 87, 77, 73, 90, 105, -17, -65, -67, -52, -85, -17, -65, -67, -55, -115, 11, -17, -65, -67, -17, -65, -67]
byte arr2[] = new byte[] {56, 99, 87, 77, 73, 90, 105, -17, -65, -67, -52, -85, -17, -65, -67, -55, -115, 11, -17, -65, -67, -17, -65, -67};
System.out.println(Arrays.toString(s.getBytes()));
System.out.println(Arrays.equals(arr, s.getBytes())); // returns false
String s2= new String(arr2);
System.out.println(Arrays.toString(s2.getBytes()));
System.out.println(Arrays.equals(arr2, s2.getBytes())); // returns true
问题内容: 我试图理解一个到字符串,一个的字符串表示形式到转换…我将我的转换成一个要发送的字符串,然后我希望我的Web服务(用python编写)将数据直接回显给客户端。 当我从Java应用程序发送数据时… 字节发送.. 发送(这是Arrays.toString()的结果,它应该是我的字节数据的字符串表示形式,该数据将通过电线发送): 在python端,python服务器将字符串返回给调用方(我可以
问题内容: 我是一名刚从C ++转到Java的学生。 在Java中,为String和Char数组定义单独的数据类型的主要原因可能是什么? 两者有什么区别? 由于我只学习过C ++,所以直到现在我仍对它们有同感。请尽可能澄清。 问题答案: 是一成不变的。数组不是。字符串是在下面用char数组实现的,但是每次您尝试对其进行修改(例如,使用串联,替换等)时,它都会为您提供一个 新 对象。 因此,它表现为
我需要通过Java socket发送一个文本消息到服务器,然后发送一个字节数组,然后是一个字符串等等。到目前为止,我所开发的内容还在工作,但客户端只读取发送的第一个字符串。 从服务器端:我使用发送字节数组,使用发送字符串。 问题是客户机和服务器不同步,我的意思是服务器发送字符串然后字节数组然后字符串,而不等待客户机消耗每个需要的字节。 我的意思是情况不是这样的:
问题内容: 在Java中,如果我有一个String ,如何计算该字符串中的字节数? 问题答案: 字符串是字符列表(即代码点)。表示字符串所用的字节数完全取决于你使用哪种编码将其转换为字节。 也就是说,你可以将字符串转换为字节数组,然后按如下所示查看其大小: 因此,你看到,即使是简单的“ ASCII”字符串,其表示形式也可以具有不同数量的字节,具体取决于所使用的编码。使用你感兴趣的字符集作为的参数。
问题内容: 如何从某个包含数字,字母等的字符串中获取字节数组?如果您熟悉Java,那么我正在寻找与getBytes()方法相同的功能。 我尝试了如下代码段: 但没有成功,因此将不胜感激。 PS:为什么我完全需要这个!好吧,我需要通过fputs()将字节数组发送到用Java编写的服务器… 问题答案: @Sparr是正确的,但是我想您期望像C#中那样的字节数组。它与Sparr的解决方案相同,但是您希望
问题内容: 我有以下代码,我试图通过测试,但似乎无法理解Java世界中各种编码形式。 我想我的问题是:将任意字节的字节数组转换为Java字符串,然后将同一Java String转换为另一个字节数组的正确方法是什么,该字节数组将具有与原始字节相同的长度和相同的内容数组? 问题答案: 尝试特定的编码: ideone链接