内部类:在一个类中定义的类,那个在类中被定义的类叫做内部类。
内部类包括成员内部类、局部内部类、匿名类。
一、成员内部类
语法
public class OuterClass{ //外部类
private class InnerClass{ //内部类
//...
}
}
外部类创建内部类实例与其他类创建对象引用时相同,在内部类中可以随意使用外部类的成员方法及变量,尽管这些类成员被修饰为private,但是内部类的成员只有在内部类的范围之内是可知的,不能被在外部类使用。
public class OuterClass{
private int i=0;
private void g(){
}
class InnerClass {
void f(){
g();
i++;
}
}
}
如果在外部类和非静态方法之外实例化内部类对象,需要使用外部类。内部类的形式指定该对象的类型。
如果不适用doit()方法返回内部类对象引用,可以直接使用内部类实例化内部类对象,但由于是在主方法中实例化内部类对象,必须在new操作符之前提供一个外部类的引用,不能在 new操作符之前使用外部类名称实例化内部类对象,而是应该使用外部类的对象来创建内部类的对象。
注意:内部类对象会依赖于外部类对象,除非已经存在一个外部类对象,否则类中就不会出现内部类对象。没有外部类对象就没有内部类对象。
用途:由于内部类向上转型为接口,在程序中可以完全隐藏内部类的实现过程,所以在实现该接口的内部类中实现该接口的方法,就可以定义多个内部类以不同的方式实现接口中的同一方法,而在一般的类中是是不能多次实现接口中的同一个方法的,可以应用在Swing编程,在一个类中做出多个不同的响应式。
注意:非内部类不能被声名为private或protect访问类型。
如果在外部类中的定义的成员变量与内部类的成员变量名称相同,可以使用this关键字进行区分。
x++; //调用形参x
this.x++; //调用内部类变量x
TheSameName.this.x++; //调用外部类变量x
在内存中所有对象均放置在堆中,方法以及方法的形参或局部变量放置在栈中。
二、局部内部类
内部类不仅可以在类中进行定义,也可以在类的局部位置定义,在类的方法或任意的作用域中均可以定义内部类,叫做局部内部类。
如果在方法中使用局部变量,该局部变量需要被设置为final类型,在方法中定义的内部类只能访问方法中final类型的局部变量。
在方法中定义的局部变量相当于一个常量,他的生命周期超出方法的运行周期,由于该局部变量被设置为final,所以不能在内部类中改变该局部变量的值。
三、匿名内部类
语法:
return new A{
...//内部类体
};
Class OuterClass4{
public OutInterface2 doit(){ //定义doit()方法
return new OutInterface2(){ //声明匿名内部类
private int i=0;
public int getValue{
}
return i;
};
}
}
由于匿名内部类没有名称,所以匿名内部类使用默认构造方法来生成OutInterface2对象。
在匿名内部类定义结束后,需要加分号标识,这个分号并不是代表定义内部类结束的标识,而是代表创建OutInterface2引用表达式的标识。
四、静态内部类
在内部类前添加修饰符static,这个内部类就变为静态内部类,一个静态内部类中可以声明static成员,但是在非静态内部类不可以声明静态成员。静态内部类有一个最大的特点,就是不可以使用外部类的非静态成员,所以静态内部类在程序开发中比较罕见。
特点:
1、如果创建静态内部类的对象,不需要其外部类的对象
2、不能从静态内部类的对象中访问非静态外部类的对象。
如果在每一个Java文件中都设置一个主方法都设置一个主方法,将出现很多额外代码,而程序本身不需要这些主方法,为了解决这个问题,可以将主方法写入静态内部类中。
五、内部类的继承
内部类和其它的类一样可以被继承,在某个类继承内部类时,必须硬性给予这个类一个带参数构造方法,并且该构造方法1的参数为需要继承内部类的外部类引用,同时在构造方法体中使用a.super()语句,这样才为继承提供了必要的对象引用。
public class OutputInnerClass extends ClassA.ClassB{ //继承内部类ClassB
public OutputInnerClass(Class A){
a.super();
}
}
class ClassA{
class ClassB{
}
}