内部类可以分为:成员内部类和局部内部类,而成员内部类又可以分为静态的成员内部类和非静态的成员内部类,而局部内部类就只有非静态的,没有静态的;
成员内部类:定义在一个类内部的类
首先来讨论非静态的成员内部类,这相当于类的非静态成员,因此可以用权限符来修饰,包括private、protected、public;对于非静态的成员内部类,其创建方式分两种情况而定:
ü 如果方法是静态方法,那么创建非静态的成员内部类前就必须先创建外部类,基本语法是:
<外部类类名>.<内部类类名> 引用变量名称 = <外部类对象的引用>.new <内部类构造器>
<外部类类名>.<内部类类名> 引用变量名称 = new <外部类构造器>.new<内部类构造器>
ü 如果方法是非静态的方法,那么创建非静态内部类就可以按照普通的创建类的方法.
例如:
package test;
public class OutterClass {
private class InterClass {
private String s = "Non Static InterClass";
}
public void test() {//非静态方法
System.out.println("--- 非静态方法调用非静态内部类 ---");
InterClass ic = new InterClass();//普通方法创建
System.out.println(ic.s);
}
public static void main(String[] args) {//静态方法
//InterClass ic = new InterClass();//非法
System.out.println("--- 静态方法调用非静态内部类 ---");
OutterClass oc = new OutterClass();
OutterClass.InterClass ic = oc.new InterClass();
//必须先创建外部类
System.out.println(ic.s);
oc.test();
}
}
打印结果:
--- 静态方法调用非静态内部类 ---
Non Static InterClass
--- 非静态方法调用非静态内部类 ---
Non Static InterClass
内部类编译后生成的.class文件名称格式是<外部类类名>$<内部类类名>
内部类可以访问外部类的任何成员,包括private成员,例如:
package test;
public class OutterClass1 {
private int i = 1;
private class InterClass {
public void test() {
System.out.println("Visit The OutterClass member: " + i);
//访问外部类的私有成员i,该成员也可以是静态的
}
}
public static void main(String[] args) {
OutterClass1.InterClass ic =
new OutterClass1().new InterClass();
ic.test();
}
}
打印结果:
Visit The OutterClass member: 1
而外部类访问内部类的成员需要创建内部类的对象,之后可以访问内部类的任何成员,包括private成员,需要注意的是非静态的成员内部类不可以有静态成员;但在静态的成员内部类中却是可以定义非静态成员的;如下是不允许的:
public class OutterClass {
class InterClass {//非静态成员内部类
static int i = 3;//不能定义了静态的成员变量;
static void run() {
}//也不能定义静态的方法;
}
}
当外部类的成员和内部类的成员重名时单单用this是区分不了的,在内部类中访问外部类的成员可以用如下语句:<外部类类名>.this.<外部类中需要被访问的成员名>
public class OutterClass {
private int i = 1;
private class InterClass {
private int i = 2;
public void run() {
System.out.println(i);//打印的是内部类的成员变量i的值
System.out.println(OutterClass.this.i);
//这个打印的才是外部类的成员变量i的值
}
}
public static void main(String[] args) {
OutterClass oc = new OutterClass();
OutterClass.InterClass ic = oc.new InterClass();
//注意:直接InterClass ic = new InterClass();是不行的
ic.run();
}
}
打印结果:2和1
接下来我们来讨论静态的成员内部类,即用static修饰class;
静态内部类的使用目的:在定义内部类的时候,可以在其前面加上一个权限修饰符
static。此时这个内部类就变为了静态内部类。如在进行代码程序测试的时候,如果在每一个Java源文件中都设置一个主方法(主方法是某个应用程序的入口,必须具有),那么会出现很多额外的代码。而且最主要的时这段主程序的代码对于Java文件来说,只是一个形式,其本身并不需要这种主方法。
但是少了这个主方法又是万万不行的。在这种情况下,就可以将主方法写入到静态内部类中,从而不用为每个Java源文件都设置一个类似的主方法。这对于代码测试是非常有用的。在一些中大型的应用程序开发中,则是一个常用的技术手段。
为此,这个静态内部类虽然不怎么常用,但是程序开发人员还必须要掌握它。也许在某个关键的时刻,其还可以发挥巨大的作用也说不定。
ü 只有将某个内部类修饰为静态类,然后才能够在这个类中定义静态的成员变量与成员
方法。这是静态内部类都有的一个特性。也正是因为这个原因,有时候少了这个静态的内部类,很多工作就无法完成。或者说要绕一个大圈才能够实现某个用户的需求。这也是静态的内部类之所以要存在的一个重要原因,例如:
package test;
public class OutterClass2 {
private static class InterClass {
private static int i = 1;//允许定义静态成员变量
public static void test() {}//允许定义静态成员方法
}
}
ü 如果一个内部类被定义为静态的,那么在引用外部类的成员方法或则成员变量的时
候,就会有诸多的限制。如不能够从静态内部类的对象中访问外部类的非静态成员(包括成员变量与成员方法)。
这是什么意思呢?如果在外部类中定义了两个变量,一个是非静态的变量,一个是静态的变量。那么在静态内部类中,无论在成员方法内部还是在其他地方,都只能够引用外部类中的静态的变量,而不能够访问非静态的变量。
在静态内部类中,可以定义静态的方法(也只有在静态的内部类中可以定义静态的方法),在静态方法中引用外部类的成员。但是无论在内部类的什么地方引用,有一个共同点,即都只能够引用外部类中的静态成员方法或者成员变量。
对于那些非静态的成员变量与成员方法,在静态内部类中是无法访问的。这就是静态内部类的最大使用限制。在普通的非静态内部类中是没有这个限制的。
也正是这个原因,决定了静态内部类只应用在一些特定的场合。其应用范围远远没有像非静态的内部类那样广泛。如下是非法的:
public class OutClass {
private int i = 1;
private static class InterClass {
public void run() {
System.out.println(i);
//静态内部类不能访问外部类中的非静态成员变量
}
}
}
局部内部类:内部类定义在方法中称为局部内部类,只在局部有效,该类只为所在的
方法块服务。
局部内部类和成员内部类一样可以访问外部类的所有成员(不过要先new出一个外围类的实例),但是不可以访问同在一个局部块的普通局部变量,如果一定要访问,此局部变量要被声明为final;
局部内部类不能使用权限符修饰,而只能使用final、abstract进行修饰;
局部内部类生成的.class文件是<外部类类名>$<n><内部类类名>其中n是该局部的第几个内部类;
下面是局部内部类的一个实例:
package test;
public class OutterClass4 {
private int i = 1;
public void test() {
//int i = 2;
//这里可以重新定义i,但是后面内部类中调用i的时候就会以为调用的是局部的i而报错!
int j = 2;
class InterClass {
public void test() {
System.out.println(i);//合法,可以访问外部类的任何成员
//System.out.println(j);//非法,不能访问局部的成员变量
}
}
}
}
还有一种类,是和主类(与文件名相同的那个类)处在同一级别上的类,也是不能用权限符修饰的,可以使用final和abstract修饰,而主类则是一定要用public权限修饰的,这种类可以与成员内部类重名,但是调用的时候会优先调用成员内部类;