1.四种内部类:成员内部类、局部内部类、匿名内部类和静态内部类。java
2.成员内部类this
2.1成员内部类能够无条件访问外部类的全部成员属性和成员方法(包括private成员和静态成员)。spa
2.2成员内部类隐藏现象指针
不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认状况下访问的是成员内部类的成员。若是要访问外部类的同名成员,须要如下面的形式进行访问:code
1对象 2继承 |
|
虽然成员内部类能够无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么为所欲为了。在外部类中若是要访问成员内部类的成员,必须先建立一个成员内部类的对象,再经过指向这个对象的引用来访问:ci
2.3内部类能够拥有private访问权限、protected访问权限、public访问权限及包访问权限。
2.4为何成员内部类能够无条件访问外部类的成员?
编译器会默认为成员内部类添加了一个指向外部类对象的引用,虽然咱们在定义的内部类的构造器是无参构造器,编译器仍是会默认添加一个参数,该参数的类型为指向外部类对象的一个引用,因此成员内部类中的Outter this&0 指针便指向了外部类对象,所以能够在成员内部类中随意访问外部类的成员。从这里也间接说明了成员内部类是依赖于外部类的,若是没有建立外部类的对象,则无 法对Outter this&0引用进行初始化赋值,也就没法建立成员内部类的对象了。
3.局部内部类
3.1局部内部类是定义在一个方法或者一个做用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该做用域内。
3.2注意,局部内部类就像是方法里面的一个局部变量同样,是不能有public、protected、private以及static修饰符的。
4.匿名内部类
匿名内部类是惟一一种没有构造器的类。正由于其没有构造器,因此匿名内部类的使用范围很是有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由 系统自动起名为Outter$1.class。通常来讲,匿名内部类用于继承其余类或是实现接口,并不须要增长额外的方法,只是对继承方法的实现或是重写。
4.1.为何局部内部类和匿名内部类只能访问局部final变量?
public class Test { public static void main(String[] args) { } public void test(final int b) { final int a = 10; new Thread(){ public void run() { System.out.println(a); System.out.println(b); }; }.start(); } }
上段代码中,若是把变量a和b前面的任一个final去掉,这段代码都编译不过。咱们先考虑这样一个问题:
当test方法执行完毕以后,变量a的生命周期就结束了,而此时Thread对象的生命周期极可能尚未结束,那么在Thread的run方法中继续访问变量a就变成不可能了,可是又要实现这样的效果,怎么办呢?Java采用了 复制 的手段来解决这个问题。
也就说若是局部变量的值在编译期间就能够肯定,则直接在匿名内部里面建立一个拷贝。若是局部变量的值没法在编译期间肯定,则经过构造器传参的方式来对拷贝进行初始化赋值。
从上面能够看出,在run方法中访问的变量a根本就不是test方法中的局部变量a。这样一来就解决了前面所说的 生命周期不一致的问题。可是新的问题又来了,既然在run方法中访问的变量a和test方法中的变量a不是同一个变量,当在run方法中改变变量a的值的 话,会出现什么状况?
对,会形成数据不一致性,这样就达不到本来的意图和要求。为了解决这个问题,java编译器就限定必须将变量a限制为final变量,不容许对变量a进行更改(对于引用类型的变量,是不容许指向新的对象),这样数据不一致性的问题就得以解决了。
到这里,想必你们应该清楚为什么 方法中的局部变量和形参都必须用final进行限定了。
5.静态内部类
静态内部类也是定义在另外一个类里面的类,只不过在类的前面多了一个关键字static。 静态内部类是不须要依赖于外部类的,这点和类的静态成员属性有点相似,而且它不能使用外部类的非static成员变量或者方法,这点很好理解,由于在没有 外部类的对象的状况下,能够建立静态内部类的对象,若是容许访问外部类的非static成员就会产生矛盾,由于外部类的非static成员必须依附于具体 的对象。