书上看到的一个问题,整理下来
简述一下内部类的实质是什么?
内部类是Java的类的一种形式,它的使用语法比较奇怪
分析:
package abc; class A {//定义外部类A class B {//定义内部类B ... } }
对于B类来说,它的完整类名就是abc.A.B,命名空间进一步缩小了,并且B对A产生了一种依赖关系,只有A存在的时候B才存在。
根据内部类定义结构的不同, 可以把内部类分为两种:成员式和局部式。成员式内部类指的是它们定义的地方与成员变量和成员方法类似,就好像一个类的成员一样。局部式内部类则是定义在方法体中,仅属于局部范围所有。
然后成员式内部类又分为:静态内部类和成员内部类。局部式又可以分为:普通局部内部类和匿名内部类。
1、静态内部类
package abc; class Outter {//定义外部类Outter static class Inner {//定义静态内部类Inner ... } }
在外部类加载的时候,静态内部类也随之加载,它的完整类名是abc.Outter.Inner,编译后的class文件名为“Outer$Inner.class”。由于静态内部类是静态的,所以它无法访问外部类的非静态成员。其实,静态内部类相对于外部类来说,几乎是独立的,它可以在没有外部类对象的情况下,单独创造一个内部类的对象。(某种程度上来说,公开的静态内部类就相当于一个普通的类)
总结一下,静态内部类相对于外部类来说,仅仅是包含关系,缩小了命名空间,完整的类名中多了一个外部类的名称。本质上是独立的两个类,JVM也不知道他们两个有包含关系。
2、成员内部类
没有使用static修饰的内部类,例如下面的代码:
package abc; class Outter {//定义外部类Outter class Inner {//定义成员内部类Inner ... } }
此时的内部类需要等外部类创建了对象以后才会被加载到JVM中,它属于外部类的某个实例,因此它可以访问外部类的静态和非静态成员。创建成员内部类的时候,语法比较特殊,首先创建一个外部类的实例,然后用这个实例调用new语句,代码如下:
public static void main(String[] args) { Outter o = new Outter();//创建外部类实例 Outter.Inner i = o.new Inner();//创建内部类实例 }
对于成员内部类的构造方法来说,系统会自动为他加上一个外部类的参数以及一个外部类的成员变量,这是为了遵循先有外部类实例才能有内部类实例的原则,代码如下:
class Inner(Outter o){//成员内部类的本质构造方法 this.o = o; }
当内部类访问外部类的成员时,则是通过该自动添加的成员变量进行访问,就好像下面的代码
o.abc();
3、局部内部类
局部内部类就没有范围的概念了,它仅在定义它的方法中有效,例如下面的代码:
public void adc(){ //成员方法 class MyLocal{ //定义局部内部类 ... //局部内部类体 } }
本质上来说,局部内部类它也是以独立的类,只不过它的一些使用受到了限制,例如,它不能使用static关键字,只能使用final、abstract关键字,仅可以访问外部类带有final关键字的局部变量,因为它访问的是一个字面量或镜像,该局部变量已经不存在了。但是,它可以任意的访问外部类对象的成员变量。
说明:与成员内部类类似,局部内部类的构造方法也会自动加上一个外部类型的参数,以及为该内部类加一个外部类型的成员变量。
当局部内部类定义在静态方法中时就相当于静态内部类:当定义在普通的成员方法中时,则相当于成员内部类。
4、匿名内部类
如果一个局部内部类没有名字,则它就是匿名内部类,例如下面的代码:
public void adc(){ //成员方法 new OneInterface(){ //直接new一个接口 public void interMethod(){//接口方法 ... } }; }
在以上代码中,匿名内部类的定义和使用根本没有出现class关键字,但事实上它还是创建了。该类实现了OneInterface接口,直接在方法体中就提供具体的实现,如果需要提供构造方法的参数,则直接在OneInterface后边的那个括号中提供即可,显得非常的灵活。其实,它的工作原理相当于局部内部类,只是没有一个具体的名字而已,外部也无法直接使用它。
注意:匿名内部类编译后的class文件的命名是按照匿名内部类的排列顺序来进行的,直接在外部类后面加上“$”和序号,例如Outter$1.class。
【答案】
内部类根据定义的情况可以分为以下4种。
(1)静态内部类:它相当于外部类的静态成员一样,使用static修饰的内部类,它隶属于外部类,使用起来相当于一个独立的外部类。
(2)成员内部类:它相当于外部类普通的成员一样,隶属于外部类的具体对象,在定义它的时候,需要先创建外部类对象,再创建它的实例。
(3)局部内部类:它定义在一个方法的方法体中,它往往仅作为方法短暂的使用,只能访问用final修饰的局部变量。
(4)匿名内部类:它也定义在方法体中,但是没有一个具体的名字,具有非常大的灵活性,工作本质与局部内部类类似。