【发布时间】:2016-03-17 20:41:37
【问题描述】:
我正在使用函数更改字符串值(我知道它非常不安全和危险):
public static void reverse(String s) {
try {
Field val = String.class.getDeclaredField("value");
val.setAccessible(true);
char[] value = (char[]) val.get(s);
char[] inverse = s.toCharArray();
for (int i = 0; i < s.length(); i++)
value[i] = inverse[s.length()-i-1];
}
catch (Exception e) {
e.printStackTrace();
}
}
之后,我发现根据字符串的创建,它的行为极其不可预测。我用它创建了一个小型智力游戏(需要大量打印才能获得想要的效果):
public static void main(String[] args) {
final String a = "abc";
final String b = new String("abc");
final String c = "abcd".substring(0, 3);
System.out.println("Let's start!");
System.out.print("a - ");
System.out.println(a);
System.out.print("b - ");
System.out.println(b);
System.out.print("c - ");
System.out.println(c);
System.out.print("Are they all equals? - ");
System.out.println(a.equals(b) && a.equals(c) && b.equals(c));
System.out.print("But they are different objects, right? - ");
System.out.println(!(a == b || b == c || a == c));
System.out.println("Let's reverse only 'a'. But all are final and String is not mutable, so what can go wrong?");
reverse(a);
System.out.println("Done. What we've got here?");
// trick 1
System.out.print("a = ");
System.out.print(a);
System.out.println(" - ok, 'a' is reversed. A bit strange, but it works. Super method");
System.out.print("b = ");
System.out.print(b);
System.out.println(" - wait... We haven't touched this");
System.out.print("c = ");
System.out.print(c);
System.out.println(" - this is untouched, wierd, huh? We've just reversed 'a' so 'b' and 'c' should act the same.");
// trick 2
System.out.println("\nOk, so 'c' should equals \"abc\", right?\n");
System.out.println("\"abc\".equals(c)? = "+"abc".equals(c));
System.out.println("...\n");
System.out.print("Do you remeber, that");
System.out.print(" a = ");
System.out.print(a);
System.out.print(" oraz b = ");
System.out.print(b);
System.out.println(" ?\n");
// trick 3
System.out.println("So let's check that");
System.out.print("a.equals(b) = ");
System.out.println(a.equals(b)+"\n");
System.out.println("Ok, we had expected that.\n");
System.out.println("But what do you think the result of (\" \"+a).equals(\" \"+b) will be?\n");
System.out.print("(\" \"+a).equals(\" \"+b) = ");
System.out.println((" "+a).equals(" "+b)+"\n");
System.out.print("And do you remeber, that");
System.out.print(" a = ");
System.out.print(a);
System.out.print(" ,a c = ");
System.out.print(c);
System.out.println(" ?\n");
// trick 4
System.out.println("So let's check if they are different:");
System.out.print("a.equals(c) = ");
System.out.println(a.equals(c));
System.out.println("So they are different... but are they really different?\n");
System.out.print("(\" \"+a).equals(\" \"+c) = ");
System.out.println((" "+a).equals(" "+c));
System.out.println("Booo!!! You could choose the blue pill!\n");
System.out.println("Our actors were: ");
System.out.print("a = ");
System.out.print(a);
System.out.print(", b = ");
System.out.print(b);
System.out.print(", c = ");
System.out.print(c);
System.out.print(" oraz abc = ");
System.out.println("abc");
System.out.print("\n");
// trick 5
System.out.println("Or in other words");
System.out.println("a = "+a+", b = "+b+", c = "+c+" oraz abc ="+(" "+"abc")+"\n");
System.out.println("But do you remember what we were revering? Was is rally b?");
System.out.println("Have a nice day. Z-DNA");
}
但我不明白那场戏。所有字符串都是不同的对象,但具有相同的值。
那么为什么在技巧 1 中,字符串 'c' 的行为与 'b' 不同呢?
好的,我明白了技巧 2。“abc”不再是“abc”而是“cba”(但是为什么?我更改了字符串 'a' 的值,而不是字符串池的值)所以它不可能等于“abc”,但是当我什至不能让“abc”调用“abc”时,“c”怎么可能是“abc”?
为什么在技巧 3 中添加空格 'a' 和 'b' 后不再相等,为什么在地球上 4 'a' 和 'c' 与空格 是相等的?!?!
技巧 5 向我们展示了 'a'、'b'、'c' 和 "abc" 的值的变化取决于我们如何称呼它。 (哦,等等。'c' 很特别。创建字符串的最不合理的方法实际上最不受黑魔法的影响)。
请帮助我了解我实际做了什么,以及函数反转是什么样的黑暗。
【问题讨论】:
-
这里的问题太多了,我懒得一一回答了。第一个问题的答案很简单。
new String("abc")创建一个new实例,但它与"abc"共享相同的支持数组。 -
当然是不可预知的。这就是为什么。
-
@LouisWasserman - 好的,但它是只有当你无法理解发生了什么时才能预测。它是可重复的,所以它可以被解释。
-
就目前而言,我认为这个问题不适合 StackOverflow。你撕掉了一个字符串的核心并提出了六个问题。 RealSkeptic 帮您写了六个答案。一些有趣的东西,但格式和呈现方式使其不太可能在未来对任何人有用。