Entity classes for testing
@Data @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 hashMap.put("hiObj",studentMap); //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"); student.setLesson("Java").setName("HH").setNo(2); //After modification System.out.println("After change:"+hashMap.get("hiObj")); System.out.println("After change:"+hashMap.get("stu")); System.out.println("After change:"+hashMap); console: 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()); console: 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")); console; 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); console: 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)); console: 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)); console: 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 = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); 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