2017-04-06 47 views
3

我正在玩String及其构造函数,并注意到我无法解释的一些行为。“否定”一个字符串会产生意想不到的行为

我创建了以下方法

public static String negate(String s) { 
    byte[] b = s.getBytes(); 
    for (int i = 0; i < b.length; i++) { 
     b[i] = (byte)(~b[i] + 1); 
    } 
    System.out.println(Arrays.toString(b)); 
    return new String(b); 
} 

它只是做了2对每个byte补充,并返回一个新的String。当调用它像

System.out.println(negate("Hello")); 

我的

[-72, -101, -108, -108, -111] 
����� 

我的猜测是好的,因为有没有负面的ASCII值的输出。
但是,当我嵌套调用像这样

System.out.println(negate(negate("Hello"))); 

我的输出是这样

[-72, -101, -108, -108, -111] 
[17, 65, 67, 17, 65, 67, 17, 65, 67, 17, 65, 67, 17, 65, 67] 
ACACACACAC // 5 groups of 3 characters (1 ctrl-char and "AC") 

我预计输出精确匹配我的输入字符串"Hello",而是我得到这个。为什么?每个其他输入字符串也会发生这种情况。嵌套之后,输入中的每个单个字符只会变成AC

我越走越创建做同样的事情的方法,而只用原料byte阵列

public static byte[] n(byte[] b) { 
    for (int i = 0; i < b.length; i++) { 
     b[i] = (byte)(~b[i] + 1); 
    } 
    System.out.println(Arrays.toString(b)); 
    return b; 
} 

这里是否如预期的输出。对于

System.out.println(new String(n(n("Hello".getBytes())))); 

我得到

[-72, -101, -108, -108, -111] 
[72, 101, 108, 108, 111] 
Hello 

所以我想它做String s的创建方式,因为它只有当我叫negate与已经得到了负byte秒的情况下发生?

我甚至走下类树看内部类,但我无法找到这种行为来自哪里。

另外在String的文档有以下段落,这可能是一个解释:

此构造函数时给出的字节是不是在默认字符集有效的行为是不确定的

灿有人告诉我为什么它是这样的,到底发生了什么?

+5

嗯,是的 - 你试图解释这仿佛他们正在编码的文本实际上并没有编码的文本任意字节。我强烈建议你不要这样做。 –

+0

如果使用映射256个字节(如ISO-8859-1例如)字符集,它的工作原理与第一种方法 – aurya

+0

而且,没有什么你正在做包括ASCII。 [String.getBytes()](https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#getBytes())可以作出但其目的是非常具体的:为了根据计算机操作系统用户的当前设置而有所不同。在我工作的任何域中都没有用。 –

回答

4

问题是你正在采取反转字节,并试图将它们解释为默认字符集中的有效字节流(请记住,字符不是字节)。所以,当你引用的字符串构造文档告诉你,结果不确定,且可能涉及纠错,丢弃无效值,等等,等等。当然,那么,这是一个有损过程,并扭转它不会让你回你原始字符串。

如果你得到的字节和双重否定没有转换中间字节为字符串,你会回来你的原始结果。

此示例演示的new String(/*invalid bytes*/)有损性质:

String s = "Hello"; 
byte[] b = s.getBytes(); 
for (int i = 0; i < b.length; i++) { 
    b[i] = (byte)(~b[i] + 1); 
} 
// Show the negated bytes 
System.out.println(Arrays.toString(b)); 
String s2 = new String(b); 
// Show the bytes of the string constructed from them; note they're not the same 
System.out.println(Arrays.toString(s2.getBytes())); 

在我的系统,我相信默认为UTF-8,我得到:

 
[-72, -101, -108, -108, -111] 
[-17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67, -17, -65, -67] 

注意,当我把发生的事无效的字节流,从中取出一个字符串,然后获取该字符串的字节。

2

你“否定”一个字符,它变得无效。然后你得到占位符(U + FFFD)。此时一切都已损坏。然后你“否定”那个,并且你从每个占位符字符中获得你的AC

+0

嗯,这取决于。 UTF-8不是任何地方的默认字符集。 –

+0

嗯,不过,这里就是这种情况,我不想将它扩展到“编码工作如何”的答案。 – Kayaman

相关问题