内部类就是在一个类中定义一各类,而这个类被称为内部类。内部类共有四种:成员内部类,静态内部类,局部内部类,匿名内部类。
一、使用内部类的好处
1.内部类可以很好的实现隐藏,一般的非内部类,是不允许有 private 与protected权限的,但内部类可以
2.内部类拥有外围类的所有元素的访问权限
3.可以实现多重继承
4.可以避免修改接口而实现同一个类中两种同名方法的调用。
二、简单介绍各种内部类
成员内部类。
成员内部类是最普通的内部类,其定义形式如下:
public class OuterClass {
private int a = 9; //外部类成员变量
private void fun() { //外部类成员函数
System.out.println("out");
}
class IntClass {
private int b = 5; //内部类成员变量
private void test() { //内部类成员变量
System.out.println("a=" + a); //调用外部类成员变量
System.out.println("b=" + b); //调用内部类成员变量
fun(); //调用外部类成员函数
}
}
public static void main(String[] argv) {
OuterClass o=new OuterClass(); //建立外部类对象
o.fun(); //调用外部类成员函数
//o.test(); //报错
IntClass i=o.new IntClass(); //建立内部类对象
//IntClass i=OuterClass.new IntClass(); //报错
i.test(); //调用内部类成员函数
}
}
运行的结果为
1 内部类与外部类是两个独立完整的类,在运行是生成各自的.class文件,如上述代码回生成OuterClass.class, IntClass.class文件。
2 内部类相当于内部类的的一个成员变量的位置,可以使用任意访问控制符,如 public 、 protected 、 private 等
3 内部类中,可以随意访问外部类的成员方法与成员变量(不受访问控制符的影响),但内部类不可以访问内部类的成员变量与成员方法。
其原因为:
内部类持有外部类的引用。
(1)编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象(this)的引用;
(2)编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为内部类中添加的成员变量赋值;
(3)在调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。
4 内部类的实例一定绑定在外部类的实例上,存在外部类对象,才能出现内部类对象。
实例化内部类的方法:
内部类 对象名 = 外部类对象.new 内部类( );(不能使用外部类名称来实例化内部类对象)
5 要调用内部类的方法只能通过实例内部类对象来调用。
·局部内部类
interface OutInterface{
void fun();
}
public class OutClass1 {
public OutInterface doit() {
class IntClass implements OutInterface {
public void fun() {
System.out.println("实现接口方法");
}
}
return new IntClass();
}
public static void main(String[] argv) {
OutClass1 o = new OutClass1();
OutInterface oi = o.doit();
oi.fun();
}
}
其运行结果为:
1 方法内部类就是内部类定义在外部类的方法中,方法内部类只在该方法的内部可见,即只在该方法内可以使用。
2 由于方法内部类不能在外部类的方法以外的地方使用,因此方法内部类不能使用访问控制符和 static 修饰符。
3 可以访问当前代码量的常量及外部类所有成员
·匿名内部类
interface OutInterface{
void fun();
}
public class OutClass2 {
public OutInterface doit() {
return new OutInterface() {
public void fun() {
System.out.println("实现接口方法");
}
};
}
public static void main(String[] argv) {
OutClass2 o = new OutClass2();
OutInterface oi = o.doit();
oi.fun();
}
}
1 匿名内部类是没有名称的,所以匿名内部类没有构造函数,不能定义静态成员,编译时会产生“外部类名$序号”为名称的.class文件。
2 必须继承一个接口或者继承一个类
3 只可以创建一个实例(通过构造块实现),不能用访问控制符,static,final,abstract修饰
4 只能使用外部类方法中的常量形参。
·静态内部类
public class OutClass {
static int a = 9;
static int b = 10;
void fun() {
System.out.println("out");
}
static class IntClass {
int b = 5;
public void test() {
System.out.println(a);
System.out.println(OutClass.b);
System.out.println(b);
new OutClass().fun();
}
public static void main(String[] argv) {
IntClass i = new IntClass();
i.test();
}
}
}
其运行结果为:
1 创建静态内部类的对象时,不需要外部类的对象,可以直接创建:
内部类 对象名= new 内部类();
2 静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问。
3 如果外部类的静态成员与内部类的成员同名,可通过 类名.静态成员 访问外部类的静态成员;
三、内部类向上转型为接口
interface OutInerface{
public void fun();
}
public class OutClass {
OutClass() {
System.out.println("new OutClass");
}
public IntClass doit() {
return new IntClass();
}
private class IntClass implements OutInerface {
IntClass() {
System.out.println("new IntClass");
}
public void fun() {
System.out.println("实现接口方法");
}
}
public static void main(String[] argv) {
OutClass o = new OutClass();
OutInerface oi = o.doit();
oi.fun();
}
}
其运行结果为:
定义一个接口,可以在一个类中定义多个内部类以不同的方法实现该接口。通过内部类实现接口,为继承外部类的子类只留下接口与方法,隐藏了方法的实现细节。
四、this的使用
当内部类与外部类成员变量或者方法相同方式,可用this进行区别调用。
public class OutClass {
private int a = 9;
void fun() {
System.out.println("out");
}
class IntClass {
private int a = 5;
void test(int a) {
int x =a; //形参a
int y = this.a; //内部类变量a
int z = OutClass.this.a; //外部类变量a
System.out.println(x + " " + y + " " + z );
}
private void fun() {
System.out.println("int");
}
}
public static void main(String[] argv) {
OutClass o = new OutClass();
o.fun();
IntClass i = o.new IntClass();
i.test(1);
i.fun();
}
}
其运行结果