Jro*_*rom 3 java string reflection immutability
我正在阅读一篇文章,说Java字符串不是完全不可变的.但是,在文章修改字符串的示例代码中,它调用string.toUpperCase().toCharArray(),它返回一个新字符串.那么,如果你调用toUpperCase(),那么通过更改字符串的过程是什么目的呢?这是代码:
public static void toUpperCase(String orig)
{
try
{
Field stringValue = String.class.getDeclaredField("value");
stringValue.setAccessible(true);
stringValue.set(orig, orig.toUpperCase().toCharArray());
}
catch (Exception ex){}
}
Run Code Online (Sandbox Code Playgroud)
另外,我注意到string.toUpperCase()本身不起作用.它需要是string.toUpperCase().toCharArray().是否有一个原因?
cor*_*iKa 12
他正在获取一些他知道正确长度的字符数组(例如String的大写版本)并将其作为String的后备数组.(value在String类中调用支持数组.)
为了说明您可以将任何char数组放在那里.
字符串是不可变的,这允许您规避不变性.当然,不建议这样做 - 永远.相反,如果他说"请注意,因为人们可能会对您的代码执行此操作,我不会感到惊讶.即使您认为您的东西是安全的,也可能不是!"
这种影响是广泛的.不可变变量不再是不可变的.最终变量不再是最终的.线程安全对象不再是线程安全的.您认为可以依赖的合同,您不能再这样做了.所有这些都是因为某个工程师在某个地方遇到了问题,他无法用正常手段修复,所以他深入研究解决问题.不要'那个家伙'.
您还将注意到现在如何更改该String的hashCode.所以,如果你从未计算过该String的hashCode,它仍然为0,所以你没事.另一方面,如果你已经计算了它,当你把它放在HashMap或HashSet中时,它将不会被检索.
考虑以下:
import java.util.*;
import java.lang.reflect.*;
class HashTest {
/** Results:
C:\Documents and Settings\glowcoder\My Documents>java HashTest
Orig hash: -804322678
New value: STACKOVERFLOW
Contains orig: true
Contains copy: false
*/
public static void main(String[] args) throws Exception {
Set<String> set = new HashSet<String>();
String str = "StackOverflow";
System.out.println("Orig hash: " + str.hashCode());
set.add(str);
Field stringValue = String.class.getDeclaredField("value");
stringValue.setAccessible(true);
stringValue.set(str, str.toUpperCase().toCharArray()); //
System.out.println("New value: " + str);
String copy = new String(str); // force a copy
System.out.println("Contains orig: " + set.contains(str));
System.out.println("Contains copy: " + set.contains(copy));
}
}
Run Code Online (Sandbox Code Playgroud)
我敢打赌他这样做是为了警告不良行为,而不是表现出"酷"的伎俩.
编辑:我找到了你所指的文章,以及它所基于的文章.最初的文章指出:"这意味着如果另一个包中的类"摆弄"一个实习字符串,它会对你的程序造成严重破坏.这是好事吗?(你不需要回答;-)"我我认为这很清楚这是一个保护指南而不是如何编码的建议.
因此,如果你只用一条信息离开这个线程,那就是反射是危险的,不可靠的,而且不容小觑!
我想我不能补充已经提供的解释,所以也许我可以通过建议如何防止这种情况来增加讨论。
您可以通过使用安全管理器来防止有人以这些和其他意外方式篡改您的代码。
public static void main(String args[]){
System.setSecurityManager(new SecurityManager());
String jedi1 = "jedi";
toUpperCase(jedi1);
System.out.println(jedi1);
}
Run Code Online (Sandbox Code Playgroud)
这将在 toUpperCase 方法中生成异常,前提是您没有将所有权限授予默认策略文件中的所有代码库。(在您当前的代码中,您的异常目前已被吞下)。
| 归档时间: |
|
| 查看次数: |
2121 次 |
| 最近记录: |