简体   繁体   English

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

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

As I am studying java, I have learned that the proper way to compare 2 Strings is to use equals and not "==". 在我学习java的过程中,我了解到比较2个字符串的正确方法是使用equals而不是“==”。 This line 这条线

static String s1 = "a";
static String s2 = "a";
System.out.println(s1 == s2);

will output true because the jvm seems to have optimized this code so that they are actually pointing to the same address. 将输出true,因为jvm似乎已优化此代码,以便它们实际指向同一地址。 I tried to prove this using a great post I found here 我试图用我在这里找到的一篇很棒的帖子证明这一点

http://javapapers.com/core-java/address-of-a-java-object/ http://javapapers.com/core-java/address-of-a-java-object/

but the addresses don't seem to be the same. 但地址似乎不一样。 What am I missing? 我错过了什么?

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);
    }
}

I think you're confused on what staticFieldOffset is returning. 我认为你对staticFieldOffset返回的内容感到困惑。 It's returning the offset of the pointer to the String instance, not the address of the String itself. 它返回指向 String实例的指针的偏移量,而不是String本身的地址。 Because there are two fields, they have different offsets: ie, two pointers, which happen to have the same value. 因为有两个字段,它们有不同的偏移量:即两个指针,它们碰巧具有相同的值。

A close reading of the Unsafe javadoc shows this: 仔细阅读Unsafe javadoc可以看出这一点:

Report the location of a given field in the storage allocation of its class. 报告给定字段在其类的存储分配中的位置。 Do not expect to perform any sort of arithmetic on this offset; 不要指望对此偏移量执行任何算术运算; it is just a cookie which is passed to the unsafe heap memory accessors. 它只是一个传递给不安全堆内存访问器的cookie。

In other words, if you know where the actual Class instance is in memory, then you could add the offset returned by this method to that base address, and the result would be the location in memory where you could find the value of the pointer to the String . 换句话说,如果您知道实际的Class实例在内存中的位置,那么您可以将此方法返回的偏移量添加到该基址,结果将是内存中您可以找到指针值的位置String

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

You aren't missing anything. 你没有遗漏任何东西。 The Unsafe library is reporting what is actually happening. 不安全的库正在报告实际发生的情况。

Bytecode: 字节码:

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

Notice both Strings are put in different locations in memory, 13 and 15. 请注意,两个字符串都放在内存中的不同位置,13和15。

There is a difference between where the the variables are stored in memory, which needs a separate address, and whether a new Object is put on the heap. 变量存储在内存中的位置存在差异,需要单独的地址,以及是否将新的Object放在堆上。 In this case, it assigns two separate addresses for two variables, but it does not need to create a new String Object as it recognizes the same String literal. 在这种情况下,它为两个变量分配两个单独的地址,但它不需要创建新的String对象,因为它识别相同的String文字。 So both variables reference the same String at this point. 因此,这两个变量在此时引用相同的String。

If you want to get the Adress, you can use the answer found in this question, How can I get the memory location of a object in java? 如果你想获得Adress,你可以使用这个问题中找到的答案, 我怎样才能获得java中对象的内存位置? . Make sure you read the caveats before using, but I did a quick test and it seems to work. 确保在使用前阅读警告,但我做了一个快速测试,它似乎工作。

String declared in Java code are automatically interned . 在Java代码中声明的字符串自动扣留

So the result is the same as you would call String.intern() manually. 因此结果与手动调用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());

output: 输出:

true 真正

false

true 真正

true 真正

暂无
暂无

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

相关问题 为什么哈希码对于String s1 =“cat”和String s2 = new String(“cat”)是相同的? - Why hash code is same for String s1= “cat” and String s2= new String(“cat”)? 使用可比较或比较器接口使用String s1的顺序对String s2进行排序 - Sort String s2 using the order of String s1 using either of comparable or comparator interface 尝试设计一个函数:hasCheated(String s1,String s2,int N)求值 - Trying to design a function : hasCheated(String s1,String s2, int N) that evaluates 如何更改Student类,以便当s1 = new Student()和s2 = new Student()时,s1 == s2返回true? - How to change Student class so that s1 == s2 return true when s1 = new Student() and s2 = new Student()? String s = s1 + s2;(s1和s2是字符串文字)从何处返回? 堆或池 - Where does String s= s1+s2;(s1 & s2 are String literals) returns from? heap or pool 在连接两个String s1和s2时,生成的输出String s3将在java中创建堆或常量池吗? - on concatenating two String s1 and s2, produced output String s3 will create in heap or constant pool in java? S1包含带有正则表达式的s2 - S1 contains s2 with regex 改进我的Java方法containsSubstring(s1,s2),它查找s2是否为s1的子字符串 - Improving my Java method containsSubstring(s1, s2) which finds if s2 is a substring of s1 为什么选择System.out.println(“嘿s1 == s2:”+ s1 == s2); 打印“false”作为输出而不是打印“hey s1 == s2:false” - Why System.out.println(“hey s1==s2:”+s1==s2); prints “false” as the output instead of printing “hey s1==s2:false” 返回List的方法 <T> 带参数列表 <S1> ,列表 <S2> ,其中S1和S2延伸T. - Method returning a List<T> with parameters List<S1>, List<S2>, where S1 and S2 extends T
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM