一、問題說明
今天在review代碼時,發現了一段代碼,有點意思,主要代碼大致這樣寫的
Student student = new Student();
HashMap<String, Object> otherInfo = student.getOtherInfo();
otherInfo.put("sex", "男");
otherInfo.put("age", 23);
otherInfo.put("phone", "10086");
System.out.println(student.toString()); //沒有set,直接調用student
其中Student變量大致定義如下:
private String name;
private HashMap<String,Object> otherInfo = new HashMap<String,Object>();
public Student() {
super();
}
public Student(String name, HashMap<String, Object> otherInfo) {
super();
this.name = name;
this.otherInfo = otherInfo;
}
//getter...
//setter...
可以發現,代碼其實就是我們日常開發當中最常見的get、set操作,通過new實例化Student對象,得到對應的student 引用,再通過引用調用get方法獲取到屬性,定義一個屬性引用,指向該對象屬性具體的內存地址,然後通過引用修改屬性的值,代碼的最後並沒有看到給對象屬性set賦值的相關操作,但是實例對象的otherInfo屬性值卻發生了變化,有點費解。
後面才明白過來,如果get獲取到的屬性對應的對象類型是非final修飾的,那麼這個屬性的引用和實例化對象中該屬性指向的是同一個內存地址,所以通過屬性引用修改屬性的值,實際上就是修改實例化對象中該屬性的值。
我們可以通過equals()方法或者hashCode()來驗證這一點,在代碼運行過程中的同一時刻:
otherInfo、student.getOtherInfo()進行equals判斷得到true;
otherInfo、student.getOtherInfo()進行hashCode比較值也是一致的。
細心的同學會發現,當get的屬性是String、Integer等常量類(底層源碼final修飾)時,通過get獲取到屬性引用,給屬性引用賦值,必須通過set給對象的這個屬性進行賦值,對象的屬性值纔會改變。
這個就是這個final起的作用了,final修飾的類是不可變的,給這樣的屬性引用進行賦新值後,屬性引用也會跟着指向新的內存地址,而此時對象中的屬性指向的內存地址還是原來的,所以必須通過set來更新對象中的屬性值。
唉,看來自己還是太嫩了,理解不夠透徹,這種問題都卡主了,要保持好好學習,天天向上,哈哈哈~
二、測試代碼
1、Test類
package com.justin.test;
import java.util.HashMap;
public class Test {
public static void main(String[] args) {
Student student = new Student();
String name = student.getName();
name = "張三";
//student.setName(name);
System.out.println(student.getName());
HashMap<String, Object> otherInfo = student.getOtherInfo();
otherInfo.put("sex", "男");
otherInfo.put("age", 23);
otherInfo.put("phone", "10086");
System.out.println(student.toString());
}
}
2、Student類
package com.justin.test;
import java.util.HashMap;
public class Student {
private String name;
private HashMap<String,Object> otherInfo = new HashMap<String,Object>();
public Student() {
super();
}
public Student(String name, HashMap<String, Object> otherInfo) {
super();
this.name = name;
this.otherInfo = otherInfo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HashMap<String, Object> getOtherInfo() {
return otherInfo;
}
public void setOtherInfo(HashMap<String, Object> otherInfo) {
this.otherInfo = otherInfo;
}
@Override
public String toString() {
return "Student [name=" + name + ", otherInfo=" + otherInfo + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((otherInfo == null) ? 0 : otherInfo.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (otherInfo == null) {
if (other.otherInfo != null)
return false;
} else if (!otherInfo.equals(other.otherInfo))
return false;
return true;
}
}