在学习java时,我了解到比较2个字符串的正确方法是使用equals而不是“==”。这一行
static String s1 = "a"; static String s2 = "a"; System.out.println(s1 == s2);
将输出true,因为jvm似乎已优化此代码,以便它们实际指向同一地址。我试图用我在这里找到的一篇很棒的文章来证明这一点
http://javapapers.com/core-java/address-of-a-java-object/
但地址似乎不一样。我错过了什么?
import sun.misc.Unsafe; import java.lang.reflect.Field; public class SomeClass { static String s1 = "a"; static String s2 = "a"; public static void main (String args[]) throws Exception { System.out.println(s1 == s2); //true Unsafe unsafe = getUnsafeInstance(); Field s1Field = SomeClass.class.getDeclaredField("s1"); System.out.println(unsafe.staticFieldOffset(s1Field)); //600 Field s2Field = SomeClass.class.getDeclaredField("s2"); System.out.println(unsafe.staticFieldOffset(s2Field)); //604 } private static Unsafe getUnsafeInstance() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafeInstance.setAccessible(true); return (Unsafe) theUnsafeInstance.get(Unsafe.class); } }
答案 0 :(得分:11)
我认为你对staticFieldOffset
返回的内容感到困惑。它将指针的偏移量返回到String
实例,而不是String
本身的地址。因为有两个字段,它们有不同的偏移量:即两个指针,恰好具有相同的值。
仔细阅读Unsafe javadoc表明了这一点:
报告给定字段在其存储分配中的位置 类。不要指望对此进行任何算术运算 偏移;它只是一个传递给不安全堆内存的cookie 访问器。
换句话说,如果您知道实际的Class
实例在内存中的位置,那么您可以将此方法返回的偏移量添加到该基址,结果将是内存中的位置,您可以找到指向String
的指针的值。
答案 1 :(得分:3)
在上面的代码中,您不是要比较字符串的地址,而是比较它们“存储分配中给定字段的位置”,即保存对(相同)字符串的引用的变量的位置。
答案 2 :(得分:2)
你没有遗漏任何东西。不安全的库正在报告实际发生的情况。
字节码:
static {};
Code:
0: ldc #11; //String a
2: putstatic #13; //Field s1:Ljava/lang/String;
5: ldc #11; //String a
7: putstatic #15; //Field s2:Ljava/lang/String;
10: return
请注意,两个字符串都放在内存中的不同位置,13和15。
变量存储在内存中的位置存在差异,需要单独的地址,以及是否将新的Object放在堆上。在这种情况下,它为两个变量分配两个单独的地址,但它不需要创建新的String对象,因为它识别相同的String文字。因此,此时两个变量都引用相同的String。
如果您想获取地址,可以使用此问题How can I get the memory location of a object in java?中的答案。确保在使用前阅读警告,但我做了一个快速测试,似乎有效。
答案 3 :(得分:-3)
在Java代码中声明的字符串会自动实习。
因此结果与您手动调用String.intern()的结果相同。
String a = "aa";
String b = new String(a);
System.out.println("aa" == "aa");
System.out.println(a == b);
System.out.println(a.equals(b));
System.out.println(a.intern() == b.intern());
输出:
是真的
错误
是真的
真