Reference type? Constant pool? Wrapper class cache? Give me a chestnut

Entity classes for testing

@Accessors(chain = true)
class Student{
    private Integer no;
    private String name;
    private String lesson;

Take out the value in a map and assign it to a variable. If the variable changes, the map will also change

        //map for storing objects
        Map<String, Object> hashMap = new HashMap<>();
        //Create a studentMap to save information
        Map<Object, Object> studentMap = new HashMap<>();
        studentMap.put("sname", "hi");
        studentMap.put("sno", 1);
        studentMap.put("lesson", "Python");
        //Put in map
        //Create a new student object and put it into the map
        Student student = new Student().setNo(1).setName("OO").setLesson("C++");
        hashMap.put("stu", student);

        //Before modification
        System.out.println("Before change:"+hashMap.get("hiObj"));
        System.out.println("Before change:"+hashMap.get("stu"));
        System.out.println("Before change:"+hashMap);
        //Take out the studentMap whose key is "hiObj"
        Map<Object, Object> hiObj = (Map<Object, Object>) hashMap.get("hiObj");
        hiObj.put("sname", "HELLO");
        hiObj.put("sno", 3);
        hiObj.put("lesson", "JavaScript");

        //After modification
        System.out.println("After change:"+hashMap.get("hiObj"));
        System.out.println("After change:"+hashMap.get("stu"));
        System.out.println("After change:"+hashMap);
Before change:{sno=1, sname=hi, lesson=Python}
Before change: Student(no=1, name=OO, lesson=C++)
Before change:{stu=Student(no=1, name=OO, lesson=C++), hiObj={sno=1, sname=hi, lesson=Python}}
After change:{sno=3, sname=HELLO, lesson=JavaScript}
After change: Student(no=2, name=HH, lesson=Java)
After change:{stu=Student(no=2, name=HH, lesson=Java), hiObj={sno=3, sname=HELLO, lesson=JavaScript}}
  • Hashmap Get ("hiobj") is to assign an address to a variable. The pointer address refers to only one object. In essence, it is a modification of an object, but different variables refer to it. Hashmap The same goes for get ("stu").

Reference to string object

  • How to prove the address difference between a string constant and a new string object
String json = new String("Json");
System.out.println("json : "+json.hashCode());
String json2 = new String("Json");
System.out.println("json2 : "+json2.hashCode());
System.out.println("test addr1;"+"Cola".hashCode());
System.out.println("test addr2;"+"Cola".hashCode());      

json : 2318600
json2 : 2318600
test addr1;2106113
test addr2;2106113
  • Obviously, since the hashCode() of String type will be the same as long as it is the same String after rewriting, the address difference cannot be seen
  • Here, the native method of System is used Identityhashcode(), which is the address value of the physical memory regardless of whether the object rewrites hashCode()
String json = new String("Json");
System.out.println("json : "+System.identityHashCode(json));
String json2 = new String("Json");
System.out.println("json2 : "+System.identityHashCode(json2));
System.out.println("test addr1;"+System.identityHashCode("Cola"));
System.out.println("test addr2;"+System.identityHashCode("Cola"));

json : 939047783
json2 : 1237514926
test addr1;548246552
test addr2;548246552
  • Here we can see that the address of a new string object is different even though the string is the same, but the address directly assigned by literal is the same, because it points to the same memory address of the constant pool
  • When I failed to figure out the above map example, I thought that it just assigned the address copy of "hiObj" to the map variable hiObj, and its change would not affect the internal object state of the original hashMap, as in the following example
        Student student = new Student().setNo(new Integer(128)).setName(new String("Json")).setLesson("C++");
        System.out.println("Before change:" + student);
        System.out.println("student.getName() addr : " + System.identityHashCode(student.getName()));
        String sname = student.getName();
        System.out.println("sname addr :" + System.identityHashCode(sname));
        sname += "hui";
        System.out.println("after sname addr : " + System.identityHashCode(sname));
        System.out.println("after student.getName() addr : " + System.identityHashCode(student.getName()));

        System.out.println("student.getNo() addr : " + System.identityHashCode(student.getNo()));
        Integer num = student.getNo();
        System.out.println("num addr :" + System.identityHashCode(num));
        num += 130;
        System.out.println("after num addr : " + System.identityHashCode(num));
        System.out.println("after student.getNo() addr : " + System.identityHashCode(student.getNo()));
        System.out.println("After change:" + student);

Before change: Student(no=128, name=Json, lesson=C++)
student.getName() addr : 939047783
sname addr :939047783
after sname addr : 1237514926
after student.getName() addr : 939047783
student.getNo() addr : 548246552
num addr :548246552
after num addr : 835648992
after student.getNo() addr : 548246552
 After change: Student(no=128, name=Json, lesson=C++)
  • Both String and Integer assign addresses to variables, while the original object student Getxxx () has no effect, but the hiObj address has not changed. In essence, it is a modification of the data of this address. Whether it is modified or not, this address is always
    Referenced by the key "hiObj" of the hashMap.

Classic comparison between String object and literal String

        String s1 = "good";
        String s2 = "good";
        String s3 = new String("good");
        String s4 = "go";
        String s5 = "od";
        String s6 = new String("go");
        String s7 = new String("od");
        String s8 = "go" + "od";
        String s9 = new String("go" + "od");

        System.out.println("s1==s2 : " + (s1 == s2));
        System.out.println("s1==s3 : " + (s1 == s3));
        System.out.println("s1==s4+s5 : " + (s1 == s4 + s5));
        System.out.println("s1==s4+s6 : " + (s1 == s4 + s6));
        System.out.println("s1==s6+s7 : " + (s1 == s6 + s7));
        System.out.println("s1==s6+s5 : " + (s1 == s6 + s5));
        System.out.println("s3==s6+s7 : " + (s3 == s6 + s7));
        System.out.println("s1==s8 : " + (s1 == s8));
        System.out.println("s3==s8 : " + (s3 == s8));
        System.out.println("s1==s9 : " + (s1 == s9));
        System.out.println("s3==s9 : " + (s3 == s9));
s1==s2 : true
s1==s3 : false
s1==s4+s5 : false
s1==s4+s6 : false
s1==s6+s7 : false
s1==s6+s5 : false
s3==s6+s7 : false
s1==s8 : true
s3==s8 : false
s1==s9 : false
s3==s9 : false
  • The constant address of the same string pointing to the constant pool is the same. The difference between s4+s5 and s8 is that the two strings of s8 already exist in the constant pool at compile time and are spliced into "good", while "good" already exists in the constant pool,
    Therefore, the address is assigned to s8, while s4+s5 dynamically performs splicing during runtime, and the memory address will be reallocated to the spliced string.
  • Others related to new will allocate different memory addresses in the heap

Classic comparison of packed Integer

Student student = new Student().setNo(new Integer(128)).setName(new String("Json")).setLesson("C++");
        Integer num = student.getNo();
        System.out.println("1,num ==new Integer(128) : "+(num ==new Integer(128)));
        System.out.println("2,128 ==new Integer(128) : "+(128 ==new Integer(128)));
        System.out.println("3,num.equals(new Integer(128)) : "+num.equals(new Integer(128)));
        System.out.println("4,new Integer(128).equals(128) : "+new Integer(128).equals(128));

        Integer a=127;
        Integer b=127;
        Integer c = 0;
        Integer d = new Integer(128);
        Integer e = new Integer(128);
        Integer f = new Integer(0);
        Integer g=128;
        Integer h=128;
        System.out.println("a==b   " + (a == b));
        System.out.println("a==b+c   " + (a == b + c));
        System.out.println("a==d   " + (a == d));
        System.out.println("d==e   " + (d == e));
        System.out.println("d.equals(e)   " + d.equals(e));
        System.out.println("d==e+f   " + (d == e + f));
        System.out.println("127==e+f   " + (127 == e + f));
        System.out.println("g==h   " + (g == h));
        System.out.println("g.equals(h)   " + g.equals(h));

1,num ==new Integer(128) : false
2,128 ==new Integer(128) : true
3,num.equals(new Integer(128)) : true
4,new Integer(128).equals(128) : true
a==b   true
a==b+c   true
a==d   false
d==e   false
d.equals(e)   true
d==e+f   true
127==e+f   false
g==h   false
g.equals(h)   true
  • "= =" compare addresses, but 1 and 2 addresses are different
  • 3.4 compare values. Since the equals method overridden by Integer calls the intValue method, the final comparison is int, so it is recommended to use the equals method when comparing Integer objects.
public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        return false;
  • 127==e+f, when Integer is compared with int, it will be unpacked into int and then compared. When an operator is encountered, it will be unpacked before calculation.
  • a==b, g==h, one is true and the other is false because of IntegerCache. If the range of values is [-128127], the values are directly taken from the cache array. The memory address is the same, otherwise it is different.
private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;

        private IntegerCache() {}
//valueOf(int i) method
public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);

So far, if there is any mistake, I hope you will give me your advice

Tags: Java

Posted by pepperface on Wed, 01 Jun 2022 08:10:49 +0530