1. 成员内部类就应该访问外部类的成员!
同样的,我们以LinkdeHashMap为例,解释内部类的定位和为什么成员内部类可以访问外部类的成员变量。
上JDK源码(部分细节删除)
public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>{
private abstract class LinkedHashIterator<T> implements Iterator<T> {
Entry<K,V> nextEntry = header.after;
Entry<K,V> lastReturned = null;
int expectedModCount = modCount;
public boolean hasNext() {
return nextEntry != header;
}
public void remove() {
}
Entry<K,V> nextEntry() {
}
}
private class KeyIterator extends LinkedHashIterator<K> {
public K next() { return nextEntry().getKey(); }
}
private class ValueIterator extends LinkedHashIterator<V> {
public V next() { return nextEntry().value; }
}
private class EntryIterator extends LinkedHashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() { return nextEntry(); }
}
}
上面的LinkdeHashMap定义了一个抽象内部类和几个抽象内部类的实现类作为成员内部类。这么做的好处是什么呢,很容易看到:这样做成员内部类可以以很爽的直接使用外部类的方法和成员变量(modCount / header...)。就像我们把心脏作为内部类作为内部类定义在人体类的内部,这样一方面保护了心脏的功能不被当做普通的抽水泵使用(可见性控制),同时我们可以直接使用人体中的血液、能量等,而不需要人体再传输给心脏了(减少沟通成本)。
以上,就是说成员内部类的定位之一就是要方便的同外部类沟通。
2. 实现原理
其实现方式是,在内部类中持有一个外部类类型的变量;下面是外部类和内部类的定义,下图是反编译内部类后的输出(没有截图常量池)
public class InnerClassFinalVar {
String ss ="g g s";
class InstanceInnerClass{
private int v = 0;
private void print(){
System.out.println("InstanceInnerClass : "+ss);
}
}
}
可以看到第一行,在内部类的内部维护了一个名称为this&0, 类型为我定义的外部类,的变量,同时这个变量被finnal修饰;同时,在下图黄字部分deputfield,是编译器将外部类的的变量赋值给this&0,这样就在内部类持有了一个外部类类型的变量,用来方位外部类的成员。