繁体   English   中英

String s1 == String s2(true)但FieldOffset不同

[英]String s1 == String s2 (true) but FieldOffset is different

在我学习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);
    }
}

我认为你对staticFieldOffset返回的内容感到困惑。 它返回指向 String实例的指针的偏移量,而不是String本身的地址。 因为有两个字段,它们有不同的偏移量:即两个指针,它们碰巧具有相同的值。

仔细阅读Unsafe javadoc可以看出这一点:

报告给定字段在其类的存储分配中的位置。 不要指望对此偏移量执行任何算术运算; 它只是一个传递给不安全堆内存访问器的cookie。

换句话说,如果您知道实际的Class实例在内存中的位置,那么您可以将此方法返回的偏移量添加到该基址,结果将是内存中您可以找到指针值的位置String

在上面的代码中,您不是比较字符串的地址,而是它们“存储分配中给定字段的位置”,即保存对(相同)字符串的引用的变量的位置。

你没有遗漏任何东西。 不安全的库正在报告实际发生的情况。

字节码:

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。

如果你想获得Adress,你可以使用这个问题中找到的答案, 我怎样才能获得java中对象的内存位置? 确保在使用前阅读警告,但我做了一个快速测试,它似乎工作。

在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());

输出:

真正

真正

真正

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM