内部类
定义:在一个类中再定义一个类,则将在类中定义的那个类称为内部类。具体分为有五种:
1.成员内部类
(1)定义:在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量。
用法:在内部类中可以随意使用外部类的成员方法及成员变量。
例:
1 public class OuterClass { 2 innerClass in = new innerClass(); // 在外部类实例化内部类对象引用 3 4 public void ouf() { 5 in.inf(); // 在外部类方法中调用内部类方法 6 } 7 8 class innerClass { //内部类的定义 9 innerClass() { // 内部类构造方法 10 } 11 12 public void inf() { // 内部类成员方法 13 } 14 15 int y = 0; // 定义内部类成员变量 16 } 17 18 public innerClass doit() { // 外部类方法,返回值为内部类引用 19 // y=4; //外部类不可以直接访问内部类成员变量 20 in.y = 4;//通过内部类对象引用调用内部类成员变量 21 return new innerClass(); // 返回内部类引用 22 } 23 24 public static void main(String args[]) { 25 OuterClass out = new OuterClass(); 26 // 内部类的对象实例化操作必须在外部类或外部类中的非静态方法中实现 27 OuterClass.innerClass in = out.doit(); 28 OuterClass.innerClass in2 = out.new innerClass(); 29 } 30 }
分析:内部类可以访问外部类的成员,但内部类成员只能在内部类的范围之内是可以被使用,不能被外部类使用,但可以使用内部类对象引用调用内部类成员变量。
在上面的例子中,如果不使用doit()方法返回内部类对象的引用,可以直接使用内部类实例化内部类对象,但是由于是在主方法中实例化内部类对象,必须在new操作符之前提供一个外部类的引用。如下例子中在主方法中实例化一个内部类对象:
public static void main(String [] args){ OuterClass out = new OuterClass(); OuterClass.innerClass in = out.doit(); OuterClass.innerClass in2 = out.new innerClass(); //实例化内部类对象 }
分析:上例中在实例化内部类对象时,不能再new操作符之前使用外部类名实例化内部类对象,而是应该使用外部类发的对象来创建其内部类对象。
(2)内部类向上转型为接口
例:
1 package com.lzw; 2 interface OutInterface { // 定义一个接口 3 public void f(); 4 } 5 //主类 6 public class InterfaceInner { 7 public static void main(String args[]) { 8 OuterClass2 out = new OuterClass2(); // 实例化一个OuterClass2对象 9 // 调用doit()方法,返回一个OutInterface接口 10 OutInterface outinter = out.doit(); 11 outinter.f(); // 调用f()方法 12 } 13 } 14 15 class OuterClass2 { 16 // 定义一个内部类实现OutInterface接口 17 private class InnerClass implements OutInterface { 18 //内部类InnerClass 实现了OutIntreface接口 19 InnerClass(String s) { // 内部类构造方法 20 System.out.println(s); 21 } 22 23 public void f() { // 实现接口中的f()方法 24 System.out.println("访问内部类中的f()方法"); 25 } 26 } 27 //OuterClass2类中的方法,返回一个外部接口类型 28 public OutInterface doit() { // 定义一个方法,返回值类型为OutInterface接口 29 return new InnerClass("访问内部类构造方法"); 30 } 31 }
分析:从上述例子中可以看出,OuterClass2类中定义了一个修饰权限为private的内部类,这个内部类实现了接口,然后修改doit()方法,使该方法返回一个接口,由于内部类接口修饰权限为private,所以除了OuterClass2类可以访问内部类之外,其他类都不能访问,而可以访问OuterClass2类中的doit()方法,由于该方法返回一个外部接口看、类型,这个接口可以作为外部使用的接口。它包含一个f()方法,在继承此接口的内部类中实现了该方法,如果某个类继承了外部类,由于内部类的权限不可以向下转型为内部类InnerClass,同时也不能访问f()方法,但可以访问接口中的方法。
(3).使用this关键字获取内部类与外部类的引用
如果在外部类与内部类中同时存在一个相同名称的成员变量,可以使用this关键字
例:
public class TheSameName{ private int x; private class Inner{ public void doit(int x){ x++; // 调用形参x this.x++; //调用内部类的变量x TheSameName.this.x++; //调用外部类的变量x } } }
2.局部内部类
内部类不仅可以在类中进行定义,也可以在类的局部位置定义,如可以在类的方法或任意的作用域中均可以定义内部类。
例:
1 interface OutInterface2 { // 定义一个接口 2 } 3 class OuterClass3 { 4 public OutInterface2 doit(final String x) { // doit()方法参数为final类型 5 // 在doit()方法中定义一个内部类 6 class InnerClass2 implements OutInterface2 { 7 InnerClass2(String s) { 8 s = x; 9 System.out.println(s); 10 } 11 } 12 return new InnerClass2("doit"); 13 } 14 }
从上述代码中可以看出,内部类被定义在了doit()内部,但有一点值得注意,内部类Innerclass2时doit()方法的一部分,并非OuterClass3类中的一部分,所以在doit()方法的外部不能访问该类的内部类,但是该类的内部类可以访问当前代码块的常量以及此外部类的所有成员。例中doit()方法的参数为final类型,如果需要在方法体中使用局部变量,该局部变量需要被设置成final类型,换句话说,在方法中定义的内部类只要能访问方法中final类型的局部变量,这是因为在方法中定义的局部变量相当于一个常量,它的生命周期超出方法运行周期,由于该局部变量被设为final,所以不能在内部类中改变该局部变量的值。
3.匿名内部类
在上例中,在doit()方法中将return语句和内部定义语句合并在一起
例:
1 class OuterClass4{ 2 public Outinterface2 doit(){ 3 return new Outinterface2{ 4 private inti = 0; 5 public int getValue(){ 6 return i; 7 } 8 }; 9 } 10 }
在上例中,在doit()方法内部首先返回一个Outinterface的引用,然后在return 语句中插入一个定义内部类的代码,由于这个类没有名称,所以这里将该内部类称为匿名内部类,实质上这种内部类的作用就是创建一个实现于Outerface2接口的匿名类的对象。由于匿名类没有名称,所以匿名类使用默认构造方法来生成Outerface2对象,在匿名类内部定义结束后,需要加分号标识,这个分号并不是代表定义内部类结束的标识,而是代表创建Outinterface2引用表达式的标识。
4.静态内部类
在内部类添加修饰符static,这个内部类就变成了静态内部类,一个静态内部类钟表可以声明static成员,但是在非静态内部类中不可以声明静态成员。静态内部类有一个最大的特点,就是不可以使用外部类的非静态成员。即普通的内部类对象隐式的在外部保存了一个引用,指向创建它的外部类对象,但如果内部类被定义为static,就会有更多的限制,静态内部类具有以下两个特点:
(1)如果创建静态内部类的对象,不需要其他外部类对象;
(2)不能从静态内部类的对象中访问非静态外部类的对象。
例:
1 public class StaticinnerClass{ 2 int x = 100; 3 static class innner{ 4 void doitinner(){ 5 } 6 } 7 }
在内部类的doitInnerClass()方法中调用成员变量x,由于Inner被修饰为static形式,而成员变量x却是非static类型,所以在doitInner()方法中不能调用x变量。
在静态内部调用女主方法例:
1 public class StaticInnerClass{ 2 int x = 100; 3 static class inner{ 4 void doitInner(){ 5 } 6 public static void main(String []) args{ 7 System.out.println("a"); 8 } 9 } 10 }
上例中将生成一个名称为StaticInnerClass的独立类和一个StaticInnerClass$Inner类,只要使用java.StaticInnerClass$Inner,就可以运行主方法中的内容。
5.内部类继承
内部类和其他类一样可以被继承,但是继承内部类比继承普通类复杂,例:
类OutputInnerClass类继承ClassA类中的内部类ClassB.
1 public class OutputInnerClass extends ClassA.ClassB{ 2 public OutputInnerClass(ClassA a){ 3 a.super(); 4 } 5 } 6 class ClassA{ 7 class ClassB{ 8 } 9 }
在某个类继承内部类时,必须硬性给予这个类一个带参数的构造方法,并且该构造方法的参数为需要继承内部类的外部类的引用,同时在构造方法中使用a.super()语句,这样才为继承提供了必要的对象引用。