今天在review代码时,发现了一段代码,有点意思,主要代码大致这样写的
Student student = new Student();
HashMap 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 otherInfo = new HashMap();
public Student() {
super();
}
public Student(String name, HashMap 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来更新对象中的属性值。
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 otherInfo = student.getOtherInfo();
otherInfo.put("sex", "男");
otherInfo.put("age", 23);
otherInfo.put("phone", "10086");
System.out.println(student.toString());
}
}
package com.justin.test;
import java.util.HashMap;
public class Student {
private String name;
private HashMap otherInfo = new HashMap();
public Student() {
super();
}
public Student(String name, HashMap otherInfo) {
super();
this.name = name;
this.otherInfo = otherInfo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HashMap getOtherInfo() {
return otherInfo;
}
public void setOtherInfo(HashMap 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;
}
}