看HashSet源码时遇到的一个问题
/**
* Returns a shallow copy of this <tt>HashSet</tt> instance: the elements
* themselves are not cloned.
*
* @return a shallow copy of this set
*/
public Object clone() {
try {
HashSet<E> newSet = (HashSet<E>) super.clone();
newSet.map = (HashMap<E, Object>) map.clone();
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
为什么newSet.map = (HashMap<E, Object>) map.clone();中可以访问到newSet的map。如果没看过HashSet源码的,可以针对下面代码理解。
public class Test {
public static void main(String[] args) {
System.out.println(new Test().visitNewA());
}
Test(){}
Test(int a){
this.a=a;
}
private int a = 10;
public int visitNewA(){
int s = new Test(11).a;
return s;
}
}
代码没有任何错误,结果为11。问题是,在visitNewA()方法中,为什么可以用new Test(11).a 来访问a
------解决方案--------------------
我觉得这是一个关于JAVA深拷贝和浅拷贝的问题。
public Object clone() {
try {
HashSet<E> newSet = (HashSet<E>) super.clone(); //(1)
newSet.map = (HashMap<E, Object>) map.clone(); // (2)
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
其中(1)处是产生一个和当前HashSet对象一样的对象newSet,但是这个newSet对象里面的map引用指向的仍然是当前对象的map。所以需要(2)这行代码重新拷贝一个HashMap<E,Object>对象。这才算拷贝完成!
至于你说的测试代码,我说一下程序执行流程,你可以设置断点跟一下!
new Test().visitNewA()
等价于:
创建一个Test对象,其中a=10。
然后这个对象调用visitNewA()方法——new Test(11).a
方法内部创建一个Test局部对象,按照JAVA对象的初始化流程,a先等于10,然后等于11。然后这个局部对象访问它的成员属性a即为11.
------解决方案--------------------
这是Java语言的规定,就是这样的
详见Java Language Specification
http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6
其中说明了
明确了在包括这个private成员的最顶级Class里都是可以访问这个private成员的