将在类中再定义的那个类称为内部类,内部类可分为成员内部类、局部内部类以及匿名类
一、成员内部类
1、成员内部类简介
在一个类中使用内部类,可以在内部类中直接存取所在类的私有成员变量,语法如下:
public static OuterClass{ //外部类
private class InnerClass{ //内部类
//...
}
}
在内部类中可以随意使用外部类的成员方法以及成员变量,尽管这些类成员被修饰为private。内部类的实例一定要绑定在外部类的实例上,如果从外部类中初始化一个内部类对象,那么内部类对象就会绑定在外部类对象上。内部类初始化方式与其他类初始化方式相同,示例如下:
public class OutClass {
innerClass in = new innerClass(); //在外部类实例化内部类对象引用
public void ouf() {
in.inf(); //在外部类方法中调用内部类方法
}
class innerClass{
innerClass(){
//内部类构造方法
}
public void inf() {
//内部类成员方法
}
int y = 0; //定义内部类成员变量
}
public innerClass doit() { //外部类方法,返回值为内部类引用
//y = 4 //外部类不可以直接访问内部类成员变量
in.y = 4;
return new innerClass(); //返回内部类引用
}
public static void main(String agrs[]) {
OutClass out = new OutClass();
//内部类的对象实例化操作必须在外部类或外部类的非静态方法中实现
OutClass.innerClass in = out.doit();
OutClass.innerClass in2 = out.new innerClass();
}
}
2、内部类向上转型为接口
如果将一个权限修饰符为private的内部类向上转型为其父类对象,或者直接向上转型为一个接口,在程序中就可以完全隐藏内部类的具体实现过程。可以在外部提供一个接口,在接口中声明一个方法。如果在实现该接口的内部类中实现该接口的方法,就可以定义多个内部类以不同的方式实现接口中的同一个方法,而在一般的类中不能多次实现接口中的同一方法,这种技巧可以在一个类中做出多个不同的响应事件,示例如下:
interface OutInteface{//定义一个接口
public void f();
}
public class InterfaceInner {
public static void main(String args[]) {
OutClass2 out = new OutClass2();//实例化一个OutClass2对象
//调用doit()方法,返回一个OutInterface接口
OutInteface outinter = out.doit();
outinter.f();//调用f()方法
}
}
class OutClass2{
//定义一个内部类实现OutInterface接口
private class InnerClass implements OutInteface{
InnerClass(String s){//内部类构造方法
System.out.println(s);
}
public void f() {//实现接口中的f()方法
System.out.println("访问内部类中的f()方法");
}
}
public OutInteface doit() {//定义一个方法,返回值类型为OutInterface接口
return new InnerClass("访问内部类构造方法");
}
}
/*输出结果如下:
访问内部类构造方法
访问内部类中的f()方法
*/
3、使用this关键字获取内部类与外部类的引用
如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字,示例如下:
public class TheSameName {
private int x;
private class Inner{
private int x = 9;
public void doit(int x) {
x++; //调用形参x
this.x++; //调用内部类的变量x
TheSameName.this.x++; //调用外部类的变量x
}
}
}
二、局部内部类
内部类不仅可以在类中进行定义,也可以在类的局部位置定义,如在类的方法或任意的作用域中均可以定义内部类,示例如下:
interface OutInterface2{
//定义一个接口
}
public class OutClass3 {
public OutInterface2 doit(final String x) {//doit()方法参数为final类型
//在doit()方法中定义一个内部类
class InnerClass2 implements OutInterface2{
InnerClass2(String s){
s = x;
System.out.println(s);
}
}
return new InnerClass2("doit");
}
}
三、匿名内部类
通过如下示例来说明匿名内部类:
public class OutClass4 {
public OutInterface2 doit() { //定义doit()方法
return new OutInterface2() { //声明匿名内部类
private int i = 0;
public int getValue() {
return i;
}
};
}
}
从上述示例可以看出,在doit()方法内部首先返回一个OutInterface2的引用,然后再return语句中插入一个定义内部类的代码,由于这个类没有名称,所以这里将该内部类称为匿名内部类。匿名类的所有实现代码都需要在大括号之间进行编码,语法如下:
return new A(){
...//内容实体
};
四、静态内部类
在内部类前添加修饰符static,这个内部类就变成了静态内部类。一个静态内部类中可以声明static成员,但是在非静态内部
普通的内部类对象隐式地在外部保存了一个引用,指向创建它的外部类对象,但如果内部类被定义为static,就会有很多限制。静态内部类具有以下两个特点:
1、如果创建静态内部类的对象,不需要其外部类的对象
2、不能从静态内部类的对象中访问非静态外部类的对象
定义静态内部类的示例如下:
public class StaticInnerClass {
int x = 100;
static class Inner{
void doitInner() {
//System.out.println("外部类"+x);//调用外部类的成员变量x
}
}
}
在静态内部类中定义主方法的示例如下:
public class StaticInnerClass {
int x = 100;
static class Inner{
void doitInner() {
//System.out.println("外部类"+x);//调用外部类的成员变量x
}
public static void main(String args[]) {
System.out.println("a");
}
}
}
五、内部类的继承
内部类和其他普通类一样可以被继承,但是继承内部类比继承普通类复杂,需要设置专门的语法来完成,示例如下:
public class OutputInnerClass extends ClassA.ClassB{
public OutputInnerClass(ClassA a) {
a.super();
}
}
class ClassA{
class ClassB{
}
}
在某个类继承内部类时,必须硬性给予这个类一个带参数的构造方法,并且该构造方法的参数为需要继承内部类的外部类的引用,同时在构造方法体中使用a.super()语句,这样才为继承提供了必要的对象引用。